From 7abbc0d1213444ad5edc9b050c1b3020186981cd Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Tue, 22 Apr 2025 23:23:19 -0400 Subject: [PATCH 01/55] wip --- .pages | 1 + .../native-token-transfers/architecture.md | 1 - ntt/.pages | 3 + ntt/architecture.md | 24 +++ ntt/index.md | 0 ntt/overview.md | 153 ++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 ntt/.pages create mode 100644 ntt/architecture.md create mode 100644 ntt/index.md create mode 100644 ntt/overview.md diff --git a/.pages b/.pages index 1b165097d..befd97afb 100644 --- a/.pages +++ b/.pages @@ -4,3 +4,4 @@ nav: - tutorials - learn - 'AI Resources': ai-resources.md + - ntt \ No newline at end of file diff --git a/learn/transfers/native-token-transfers/architecture.md b/learn/transfers/native-token-transfers/architecture.md index d9f0ff37a..9c80c7c9a 100644 --- a/learn/transfers/native-token-transfers/architecture.md +++ b/learn/transfers/native-token-transfers/architecture.md @@ -8,7 +8,6 @@ categories: NTT, Transfer The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. -For the technical implementations of the functions, refer to the [Managers and Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/){target=\_blank} page. ## System Components diff --git a/ntt/.pages b/ntt/.pages new file mode 100644 index 000000000..5edcebdb5 --- /dev/null +++ b/ntt/.pages @@ -0,0 +1,3 @@ +nav: + - index.md + - overview.md diff --git a/ntt/architecture.md b/ntt/architecture.md new file mode 100644 index 000000000..b92f19b34 --- /dev/null +++ b/ntt/architecture.md @@ -0,0 +1,24 @@ +--- +title: Native Token Transfers Architecture +description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +categories: NTT, Transfer +--- + +## Native Token Transfers Architecture + +The Native Token Transfers (NTT) architecture enables secure and efficient native token transfers across blockchains. Designed for flexibility and composability, it coordinates minting, burning, and message verification through a set of on-chain contracts and cross-chain messaging. + +This page outlines the core components, how they interact, and the underlying mechanisms that ensure consistent token behavior across supported chains. + +## High-level Overview + +There are a few core components involved in NTTs: + +- NTT Manager - integrator owned contract on source chain +- Wormhole Transceiver on source chain- +- Wormhole Core Contract on source chain - +- Guardian Network +- Relayer +- Wormhole Transceiver on destination chain +- Wormhole core contract on destination chain +- NTT manager - integrator owned contract on destination chain diff --git a/ntt/index.md b/ntt/index.md new file mode 100644 index 000000000..e69de29bb diff --git a/ntt/overview.md b/ntt/overview.md new file mode 100644 index 000000000..1712b7779 --- /dev/null +++ b/ntt/overview.md @@ -0,0 +1,153 @@ +--- +title: Native Token Transfers Overview +description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. +categories: NTT, Transfer +--- + +# Native Token Transfers + +Native Token Transfers (NTT) is an open-source and composable framework for moving tokens between blockchains without relying on wrapped assets. It enables developers and protocol teams to maintain native token behavior, supply control, and unified token economics across chains. + +Unlike traditional bridges that use wrapped assets—leading to fragmented liquidity and governance complexity—NTT uses canonical token deployments and a single mint-and-burn model to keep total supply in sync. + +## Key Features + +- [x] **No wrapped assets** – tokens retain their native format on each chain +- [x] **Canonical deployments** – one unified token identity across chain +- [x] **Supply control** – enforced mint-and-burn model maintains global supply integrity +- [x] **Composable** – open-source and extensible for widespread adoption and integration with other protocols +- [x] **Customizable controls** – configure rate limits, access control, and attestation thresholds + +## Use Cases + +Generally speaking, NTT can be used by developers building multichain dApps, token issuers creating and deploying a single token across multiple chains, and governance platforms utilizing native tokens for cross-chain voting and decision-making. Below are some specific use cases where NTT provides added value: + +??? interface "Cross-chain swaps and liquidity aggregation" + + 💡 Enable seamless swaps between chains with real-time liquidity routing. + + 🛠 **Wormhole products used:** + + - [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution + + 🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators + + 🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} + +??? interface "Borrowing and lending" + + 💡 Let users borrow assets on one chain using collateral from another. + + 🛠 **Wormhole products used:** + + - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time + + 🔗 **Used in:** Lending protocols and yield platforms + + 🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} + +??? interface "Asset movement between Bitcoin and other chains" + + 💡 Enable direct BTC transfers without wrapped assets. + + 🛠 **Wormhole products used:** + + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains + + 🔗 **Used in:** Bitcoin DeFi and lightning network integrations + + 🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} + +??? interface "Memecoin launchpads" + + 💡 Launch and distribute memecoins across multiple chains, enabling cross-chain fund raising and liquidity access. + + 🛠 **Wormhole products used:** + + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising + - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes + + 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems + +??? interface "Gas abstraction" + + 💡 Allow users to pay gas fees with any token across different networks, removing fric tion in multichain interactions. + + 🛠 **Wormhole products used:** + + - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments + + 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements + +??? interface "Cross-chain payment widgets" + + 💡 Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. + + 🛠 **Wormhole products used:** + + - [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers + + 🔗 **Used in:** E-commerce, Web3 payments, and subscription models + +??? interface "Cross-chain staking" + + 💡 Enable users to stake assets on one chain while earning rewards or securing networks on another. + + 🛠 **Wormhole products used:** + + - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains + - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks + + 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks + + 🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} + +## Integration Process + +The process for creating, deploying, and monitoring NTTs is as follows. + +[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] + +## Deployment Models + +NTT offers two deployment models, each catering to different token management needs: + +- **Hub-and-spoke** + + Locks tokens on a central hub chain and mints equivalent tokens on destination spoke chains, preserving the canonical balance and enabling secure cross-chain transfers. + + Most suitable for existing token deployments that don't want to alter existing token contracts + +- **Burn-and-mint** + + Burns tokens on the source chain and mints equivalent tokens on the destination chain, creating a native multichain token and simplifying the transfer process. + + Most suitable for new token deployments or projects willing to upgrade existing contracts + +## Next Steps + +
+ +- :octicons-tools-16:{ .lg .middle } **Start building** + + --- + + Follow these steps to begin the integration process and deploy NTT. + + [:custom-arrow: Get started]() + +- :octicons-tools-16:{ .lg .middle } **Learn how NTT works** + + --- + + Discover NTT's architecture and how it enables cross-chain token transfers. + + [:custom-arrow: Explore architecture]() + +
\ No newline at end of file From a690f8992962a77d4c4006728477435a7807249f Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Thu, 24 Apr 2025 01:22:26 -0400 Subject: [PATCH 02/55] reorganize content to new structure --- {build => ..build}/core-messaging/index.md | 6 +- {build => ..build}/multigov/index.md | 10 +- {build => ..build}/queries/overview.md | 2 +- {build => ..build}/queries/use-queries.md | 2 +- .../start-building/use-cases.md | 34 +- {build => ..build}/toolkit/cli.md | 0 {build => ..build}/toolkit/dev-env.md | 8 +- {build => ..build}/toolkit/faqs.md | 2 +- {build => ..build}/transfers/cctp.md | 6 +- {build => ..build}/transfers/connect/index.md | 8 +- .../transfers/connect/overview.md | 16 +- .../deployment-process/installation.md | 6 +- .../deployment-process/post-deployment.md | 4 +- .../transfers/native-token-transfers/index.md | 6 +- .../managers-transceivers.md | 0 {build => ..build}/transfers/token-bridge.md | 37 +- {learn => ..learn}/glossary.md | 8 +- {learn => ..learn}/governance/overview.md | 4 +- {learn => ..learn}/transfers/cctp.md | 4 +- {learn => ..learn}/transfers/index.md | 0 .../native-token-transfers/deployment.md | 0 .../native-token-transfers/overview.md | 8 +- .../transfers/settlement/overview.md | 2 +- {learn => ..learn}/transfers/token-bridge.md | 12 +- .gitignore | 3 +- .pages | 10 +- .../complete-usdc-transfer}/cctp-sdk-1.ts | 0 .../complete-usdc-transfer}/cctp-sdk-2.ts | 0 .../complete-usdc-transfer}/cctp-sdk-3.ts | 0 .../complete-usdc-transfer}/cctp-sdk-4.ts | 0 .../advanced-configuration.json | 0 .../configuration-v0}/arbitrary-token.tsx | 0 .../configuration-v0}/configure-html.html | 0 .../configuration-v0}/configure-react-v0.tsx | 0 .../configuration-v0}/custom-full.jsx | 0 .../custom-simple-testnet-v0.tsx | 0 .../configuration-v0}/custom-simple-v0.jsx | 0 .../configuration/configuration-v0}/index.ts | 0 .../sample-configuration.json | 0 .../connect/configuration/data}/add-token.tsx | 0 .../configuration/data}/configure-hosted.tsx | 0 .../data}/configure-react-v1.tsx | 0 .../data}/custom-coingecko-key.jsx | 0 .../data}/custom-disable-arbitrary-tokens.jsx | 0 .../data}/custom-simple-testnet-v1.jsx | 0 .../configuration/data}/custom-simple-v1.jsx | 0 .../custom-tokens-whitelist-advanced.jsx | 0 .../data}/custom-tokens-whitelist.jsx | 0 .../data}/custom-tx-settings-solana.jsx | 0 .../configuration/data}/example-all-routes.ts | 0 .../configuration/data}/example-cctp.ts | 0 .../theme}/custom-colors-hosted.tsx | 0 .../configuration/theme}/custom-colors.tsx | 0 .../configuration/theme}/custom-menu.jsx | 0 .../core-contracts/receiveEmitterCheck.ts | 0 .../core-contracts/receiveMessageEVM.sol | 0 .../core-contracts/receiveMessageSolana.rs | 0 .../guides}/core-contracts/receiving.sol | 0 .../guides}/core-contracts/sendMessageEVM.sol | 0 .../core-contracts/sendMessageSolana.rs | 0 .../guides}/core-contracts/sending.sol | 0 .../wormhole-relayers/ExampleContract.sol | 0 .../wormhole-relayers/getQuoteAndSend.sol | 0 .../quoteEVMDeliveryPrice.sol | 0 .../receiveWormholeMessages.sol | 0 .../wormhole-relayers/sendPayloadToEvm.sol | 0 .../cross-chain-contracts/snippet-1.sol | 0 .../cross-chain-contracts/snippet-2.sol | 0 .../cross-chain-contracts/snippet-3.ts | 0 .../cross-chain-contracts/snippet-4.html | 0 .../cross-chain-contracts/snippet-5.ts | 0 .../cross-chain-contracts/snippet-6.ts | 0 .../cross-chain-contracts/snippet-7.html | 0 .../cross-chain-contracts/snippet-8.html | 0 .../cross-chain-contracts/snippet-9.json | 0 .../cross-chain-token-transfers/snippet-1.sol | 0 .../snippet-10.html | 0 .../snippet-11.sol | 0 .../cross-chain-token-transfers/snippet-2.sol | 0 .../snippet-3.json | 0 .../cross-chain-token-transfers/snippet-4.ts | 0 .../cross-chain-token-transfers/snippet-5.ts | 0 .../snippet-6.html | 0 .../snippet-7.html | 0 .../snippet-8.html | 0 .../snippet-9.json | 0 .../replace-signatures/replace-sigs-1.json | 0 .../replace-signatures/replace-sigs-10.html | 0 .../replace-signatures/replace-sigs-11.html | 0 .../replace-signatures/replace-sigs-12.ts | 0 .../replace-signatures/replace-sigs-13.html | 0 .../replace-signatures/replace-sigs-14.ts | 0 .../replace-signatures/replace-sigs-15.html | 0 .../replace-signatures/replace-sigs-16.ts | 0 .../replace-signatures/replace-sigs-17.html | 0 .../replace-signatures/replace-sigs-2.ts | 0 .../replace-signatures/replace-sigs-3.ts | 0 .../replace-signatures/replace-sigs-4.ts | 0 .../replace-signatures/replace-sigs-5.ts | 0 .../replace-signatures/replace-sigs-6.html | 0 .../replace-signatures/replace-sigs-7.ts | 0 .../replace-signatures/replace-sigs-8.html | 0 .../replace-signatures/replace-sigs-9.ts | 0 .../guides/deploy-to-evm}/INttToken.sol | 0 .../guides/deploy-to-evm}/initialize.txt | 0 .../reference/formatted-addresses/evm.ts | 0 .../reference/formatted-addresses/solana.ts | 0 .../liquidity-layer}/placeFastMarketOrder.sol | 0 .../liquidity-layer}/placeMarketOrder.sol | 0 .../guides/solver}/solver-config.json | 0 .../transfer-workflow}/token-bridge-1.ts | 0 .../transfer-workflow}/token-bridge-2.ts | 0 .../transfer-workflow}/token-bridge-3.ts | 0 .../run-relayer/snippet-1.ts | 0 .../run-relayer/snippet-2.ts | 0 .../run-relayer/snippet-3.ts | 0 .../run-relayer/snippet-4.ts | 0 .../run-relayer/snippet-5.ts | 0 .../run-relayer/snippet-6.ts | 0 .../run-relayer/snippet-7.ts | 0 .../infrastructure/VAAs/snippet-1.js | 0 .../infrastructure/VAAs/snippet-2.js | 0 .../sdk-reference}/solidity-sdk-1.sol | 0 .../sdk-reference}/solidity-sdk-2.sol | 0 .../sdk-reference}/solidity-sdk-3.sol | 0 .../sdk-reference}/solidity-sdk-4.sol | 0 .../sdk-reference}/solidity-sdk-5.sol | 0 .../guides}/protocols-payloads/pl-1.ts | 0 .../guides}/protocols-payloads/pl-2.ts | 0 .../guides}/protocols-payloads/pl-3.ts | 0 .../guides}/protocols-payloads/pl-4.ts | 0 .../guides}/protocols-payloads/pl-5.ts | 0 .../guides}/protocols-payloads/pl-6.ts | 0 .../guides}/protocols-payloads/pl-7.ts | 0 .../guides}/protocols-payloads/pl-8.ts | 0 .../guides}/sdk-layout/layout-0.ts | 0 .../guides}/sdk-layout/layout-1.ts | 0 .../guides}/sdk-layout/layout-10.ts | 0 .../guides}/sdk-layout/layout-11.ts | 0 .../guides}/sdk-layout/layout-12.ts | 0 .../guides}/sdk-layout/layout-13.ts | 0 .../guides}/sdk-layout/layout-14.ts | 0 .../guides}/sdk-layout/layout-15.ts | 0 .../guides}/sdk-layout/layout-16.ts | 0 .../guides}/sdk-layout/layout-17.ts | 0 .../guides}/sdk-layout/layout-18.ts | 0 .../guides}/sdk-layout/layout-19.ts | 0 .../guides}/sdk-layout/layout-2.ts | 0 .../guides}/sdk-layout/layout-20.ts | 0 .../guides}/sdk-layout/layout-21.ts | 0 .../guides}/sdk-layout/layout-22.ts | 0 .../guides}/sdk-layout/layout-23.ts | 0 .../guides}/sdk-layout/layout-25.ts | 0 .../guides}/sdk-layout/layout-26.ts | 0 .../guides}/sdk-layout/layout-27.ts | 0 .../guides}/sdk-layout/layout-3.ts | 0 .../guides}/sdk-layout/layout-4.ts | 0 .../guides}/sdk-layout/layout-5.ts | 0 .../guides}/sdk-layout/layout-6.ts | 0 .../guides}/sdk-layout/layout-7.ts | 0 .../guides}/sdk-layout/layout-8.ts | 0 .../guides}/sdk-layout/layout-9.ts | 0 .../guides}/vaas-protocols/solidity-sdk.sol | 0 .../guides}/vaas-protocols/ts-sdk.ts | 0 .../sdk-reference}/addresses.ts | 0 .../typescript-sdk/sdk-reference}/cctp.ts | 0 .../sdk-reference}/config-override.ts | 0 .../typescript-sdk/sdk-reference}/config.ts | 0 .../sdk-reference}/custom-route.ts | 0 .../typescript-sdk/sdk-reference}/ethers.js | 0 .../sdk-reference}/example-core-bridge.ts | 0 .../sdk-reference}/get-chain.ts | 0 .../typescript-sdk/sdk-reference}/get-vaa.ts | 0 .../typescript-sdk/sdk-reference}/router.ts | 0 .../typescript-sdk/sdk-reference}/signers.ts | 0 .../sdk-reference}/token-bridge-snippet.ts | 0 .../sdk-reference}/token-bridge.ts | 0 .../typescript-sdk/sdk-reference}/tokens.ts | 0 .../core-messaging-timeline.json | 8 +- .../transfers/connect/connect-timeline.json | 6 +- .../ntt/ntt-deployment-process-timeline.json | 4 +- .../infrastructure-index-timeline.json | 22 - .../reference/chain-ids/chain-ids.md | 0 .../consistency-levels/consistency-levels.md | 0 .../reference/contract-addresses/cctp.md | 0 .../contract-addresses/core-contracts.md | 0 .../reference/contract-addresses/read-only.md | 0 .../reference/contract-addresses/relayer.md | 0 .../contract-addresses/token-bridge.md | 0 .../testnet-faucets/testnet-faucets.md | 0 build/.pages | 11 - build/core-messaging/.pages | 5 - build/index.md | 111 --- build/infrastructure/.pages | 5 - build/infrastructure/index.md | 35 - build/infrastructure/relayers/.pages | 4 - build/infrastructure/relayers/index.md | 60 -- build/infrastructure/spy/.pages | 4 - build/infrastructure/spy/index.md | 50 -- build/multigov/.pages | 8 - build/queries/.pages | 6 - build/queries/index.md | 39 - build/reference/.pages | 7 - build/reference/index.md | 57 -- build/start-building/.pages | 8 - build/start-building/index.md | 52 -- build/toolkit/.pages | 8 - build/toolkit/index.md | 95 --- build/toolkit/typescript-sdk/index.md | 31 - build/transfers/.pages | 8 - build/transfers/connect/.pages | 9 - build/transfers/connect/configuration/.pages | 5 - .../transfers/connect/configuration/index.md | 39 - build/transfers/index.md | 79 -- build/transfers/native-token-transfers/.pages | 8 - .../configuration/.pages | 5 - .../configuration/index.md | 31 - .../deployment-process/.pages | 9 - .../deployment-process/index.md | 63 -- build/transfers/settlement/.pages | 6 - build/transfers/settlement/index.md | 31 - .../tutorials}/react-dapp/connect-1.webp | Bin .../tutorials}/react-dapp/connect-2.webp | Bin .../tutorials}/react-dapp/connect-3.webp | Bin .../tutorials}/react-dapp/connect-4.webp | Bin .../tutorials}/react-dapp/connect-5.webp | Bin .../tutorials}/react-dapp/connect-6.webp | Bin .../tutorials}/react-dapp/connect-7.webp | Bin .../wormhole-relayers/relayer-1.webp | Bin .../architecture}/multigov-detailed.webp | Bin .../architecture}/multigov-high-level.webp | Bin .../architecture/architecture-1.webp | Bin .../architecture/architecture-2.webp | Bin .../evm-launchpad/ntt-launchpad-1.webp | Bin .../evm-launchpad/ntt-launchpad-10.webp | Bin .../evm-launchpad/ntt-launchpad-11.webp | Bin .../evm-launchpad/ntt-launchpad-12.webp | Bin .../evm-launchpad/ntt-launchpad-13.webp | Bin .../evm-launchpad/ntt-launchpad-14.webp | Bin .../evm-launchpad/ntt-launchpad-15.webp | Bin .../evm-launchpad/ntt-launchpad-2.webp | Bin .../evm-launchpad/ntt-launchpad-3.webp | Bin .../evm-launchpad/ntt-launchpad-4.webp | Bin .../evm-launchpad/ntt-launchpad-5.webp | Bin .../evm-launchpad/ntt-launchpad-6.webp | Bin .../evm-launchpad/ntt-launchpad-7.webp | Bin .../evm-launchpad/ntt-launchpad-8.webp | Bin .../evm-launchpad/ntt-launchpad-9.webp | Bin .../architecture/architecture-1.webp | Bin .../architecture/architecture-2.webp | Bin .../architecture/architecture-3.webp | Bin .../multichain-tokens/multichain-token-1.webp | Bin .../multichain-tokens/multichain-token-2.webp | Bin .../multichain-tokens/multichain-token-3.webp | Bin .../multichain-tokens/multichain-token-4.webp | Bin .../multichain-tokens/multichain-token-5.webp | Bin .../architecture/architecture-1.webp | Bin .../run-relayer/relayer-1.webp | Bin .../vaas/lifetime-vaa-diagram.webp | Bin .../introduction/introduction-1.webp | Bin learn/.pages | 11 - learn/governance/.pages | 6 - learn/governance/faq.md | 26 - learn/governance/index.md | 85 -- learn/index.md | 132 --- learn/infrastructure/.pages | 9 - learn/infrastructure/index.md | 63 -- learn/transfers/.pages | 7 - learn/transfers/native-token-transfers/.pages | 7 - .../transfers/native-token-transfers/index.md | 71 -- learn/transfers/settlement/.pages | 5 - learn/transfers/settlement/index.md | 31 - llms-files/llms-basics.txt | 180 ++--- llms-files/llms-connect.txt | 258 +++--- llms-files/llms-multigov.txt | 240 +++--- llms-files/llms-ntt.txt | 312 ++++---- llms-files/llms-queries.txt | 190 ++--- llms-files/llms-reference.txt | 34 +- llms-files/llms-relayers.txt | 204 ++--- llms-files/llms-settlement.txt | 214 ++--- llms-files/llms-solidity-sdk.txt | 208 ++--- llms-files/llms-token-bridge.txt | 198 ++--- llms-files/llms-transfer.txt | 452 +++++------ llms-files/llms-typescript-sdk.txt | 226 +++--- llms-full.txt | 756 +++++++++--------- llms.txt | 120 +-- ntt/.pages | 3 - ntt/architecture.md | 24 - ntt/overview.md | 153 ---- products/.pages | 11 + products/cctp-bridge/.pages | 7 + products/cctp-bridge/concepts/.pages | 4 + products/cctp-bridge/concepts/integration.md | 1 + products/cctp-bridge/get-started.md | 1 + products/cctp-bridge/guides/.pages | 3 + products/cctp-bridge/guides/transfer-usdc.md | 1 + products/cctp-bridge/overview.md | 1 + products/cctp-bridge/tutorials/.pages | 3 + .../tutorials/complete-usdc-transfer.md | 42 +- products/connect/.pages | 10 + products/connect/concepts/.pages | 3 + .../connect/concepts}/routes.md | 6 +- products/connect/configuration/.pages | 4 + .../configuration}/configuration-v0.md | 20 +- .../connect/configuration/data.md | 26 +- .../connect/configuration/theme.md | 6 +- {build/transfers => products}/connect/faqs.md | 8 +- products/connect/get-started.md | 1 + products/connect/guides/.pages | 3 + .../connect/guides}/upgrade.md | 4 +- products/connect/overview.md | 1 + products/connect/reference/.pages | 3 + .../connect/reference/support-matrix.md | 2 +- products/connect/tutorials/.pages | 4 + .../connect/tutorials}/react-dapp.md | 18 +- products/messaging/.pages | 6 + products/messaging/get-started.md | 1 + products/messaging/guides/.pages | 4 + .../messaging/guides}/core-contracts.md | 34 +- .../messaging/guides}/wormhole-relayers.md | 20 +- products/messaging/overview.md | 1 + products/messaging/tutorials/.pages | 4 + .../tutorials}/cross-chain-contracts.md | 62 +- .../tutorials}/cross-chain-token-contracts.md | 82 +- .../tutorials}/replace-signatures.md | 78 +- products/multigov/.pages | 8 + products/multigov/concepts/.pages | 3 + .../multigov/concepts}/architecture.md | 2 +- .../faq.md => products/multigov/faqs.md | 51 +- products/multigov/get-started.md | 1 + products/multigov/guides/.pages | 6 + .../multigov/guides}/deploy-to-evm.md | 2 +- .../multigov/guides}/deploy-to-solana.md | 2 +- .../multigov/guides}/upgrade-evm.md | 0 .../multigov/guides}/upgrade-solana.md | 0 products/multigov/overview.md | 1 + products/multigov/tutorials/.pages | 3 + .../multigov/tutorials}/treasury-proposal.md | 0 products/native-token-transfers/.pages | 10 + .../native-token-transfers/concepts/.pages | 4 + .../concepts}/architecture.md | 6 +- .../concepts}/security.md | 0 .../configuration/.pages | 4 + .../configuration/access-control.md | 0 .../configuration/rate-limiting.md | 0 .../native-token-transfers/faqs.md | 2 +- .../native-token-transfers/get-started.md | 1 + products/native-token-transfers/guides/.pages | 5 + .../guides}/deploy-to-evm.md | 8 +- .../guides}/deploy-to-solana.md | 14 +- .../guides}/evm-launchpad.md | 40 +- products/native-token-transfers/overview.md | 1 + .../native-token-transfers/reference/.pages | 3 + .../reference}/cli-commands.md | 6 +- .../troubleshooting.md | 10 +- .../start-building => products}/products.md | 6 +- products/queries/.pages | 8 + products/queries/concepts/.pages | 3 + products/queries/concepts/rpc-basics.md | 1 + {build => products}/queries/faqs.md | 0 products/queries/get-started.md | 1 + products/queries/guides/.pages | 7 + products/queries/guides/construct-a-query.md | 1 + products/queries/guides/mock-a-query.md | 1 + products/queries/guides/query-request.md | 1 + .../queries/guides/submit-response.md | 0 products/queries/guides/verify-response.md | 1 + products/queries/overview.md | 1 + products/queries/reference/.pages | 4 + .../queries/reference/supported-methods.md | 1 + .../queries/reference/supported-networks.md | 1 + products/reference/.pages | 8 + {build => products}/reference/chain-ids.md | 2 +- .../reference/consistency-levels.md | 2 +- .../reference/contract-addresses.md | 10 +- .../reference}/supported-networks.md | 0 .../reference}/testnet-faucets.md | 2 +- .../reference/wormhole-formatted-addresses.md | 4 +- products/settlement/.pages | 7 + products/settlement/concepts/.pages | 3 + .../settlement/concepts}/architecture.md | 10 +- .../transfers => products}/settlement/faqs.md | 0 products/settlement/get-started.md | 1 + products/settlement/guides/.pages | 4 + .../settlement/guides}/liquidity-layer.md | 4 +- .../settlement/guides}/solver.md | 2 +- products/settlement/overview.md | 1 + .../tutorials}/.settlement-routes.md | 2 +- products/token-bridge/.pages | 9 + products/token-bridge/concepts/.pages | 4 + .../concepts/payload-structure.md | 1 + .../token-bridge/concepts/transfer-flow.md | 1 + products/token-bridge/faqs.md | 36 + products/token-bridge/get-started.md | 1 + products/token-bridge/guides/.pages | 3 + .../guides/transfer-wrapped-assets.md | 1 + products/token-bridge/overview.md | 1 + products/token-bridge/tutorials/.pages | 4 + .../tutorials}/multichain-token.md | 10 +- .../tutorials/transfer-workflow.md | 64 +- protocol/.pages | 7 + .../architecture.md | 20 +- protocol/infrastructure-guides/.pages | 4 + .../infrastructure-guides}/run-relayer.md | 18 +- .../infrastructure-guides}/run-spy.md | 2 +- protocol/infrastructure/.pages | 7 + .../infrastructure/core-contracts.md | 12 +- .../infrastructure/guardians.md | 8 +- {learn => protocol}/infrastructure/relayer.md | 10 +- {learn => protocol}/infrastructure/spy.md | 4 +- {learn => protocol}/infrastructure/vaas.md | 12 +- {learn => protocol}/introduction.md | 10 +- {learn => protocol}/security.md | 4 +- tools/.pages | 6 + tools/solidity-sdk/.pages | 4 + tools/solidity-sdk/get-started.md | 1 + .../solidity-sdk/sdk-reference.md | 24 +- tools/typescript-sdk/.pages | 5 + tools/typescript-sdk/get-started.md | 0 .../typescript-sdk/guides}/.pages | 4 +- .../guides}/protocols-payloads.md | 18 +- .../typescript-sdk/guides}/sdk-layout.md | 58 +- .../typescript-sdk/guides}/vaas-protocols.md | 12 +- .../typescript-sdk/sdk-reference.md | 58 +- tutorials/.pages | 11 - tutorials/connect/.pages | 4 - tutorials/connect/index.md | 37 - tutorials/index.md | 65 -- tutorials/multichain-assets/.pages | 4 - tutorials/multichain-assets/index.md | 22 - tutorials/multigov/.pages | 4 - tutorials/multigov/index.md | 46 -- tutorials/settlement/.index.md | 22 - tutorials/settlement/.pages | 5 - tutorials/solidity-sdk/.pages | 5 - tutorials/solidity-sdk/index.md | 44 - tutorials/typescript-sdk/.pages | 5 - tutorials/typescript-sdk/index.md | 44 - tutorials/wormholescan/.pages | 4 - tutorials/wormholescan/index.md | 36 - 440 files changed, 2640 insertions(+), 4290 deletions(-) rename {build => ..build}/core-messaging/index.md (81%) rename {build => ..build}/multigov/index.md (90%) rename {build => ..build}/queries/overview.md (98%) rename {build => ..build}/queries/use-queries.md (98%) rename {build => ..build}/start-building/use-cases.md (75%) rename {build => ..build}/toolkit/cli.md (100%) rename {build => ..build}/toolkit/dev-env.md (81%) rename {build => ..build}/toolkit/faqs.md (96%) rename {build => ..build}/transfers/cctp.md (98%) rename {build => ..build}/transfers/connect/index.md (87%) rename {build => ..build}/transfers/connect/overview.md (82%) rename {build => ..build}/transfers/native-token-transfers/deployment-process/installation.md (90%) rename {build => ..build}/transfers/native-token-transfers/deployment-process/post-deployment.md (90%) rename {build => ..build}/transfers/native-token-transfers/index.md (84%) rename {build => ..build}/transfers/native-token-transfers/managers-transceivers.md (100%) rename {build => ..build}/transfers/token-bridge.md (71%) rename {learn => ..learn}/glossary.md (82%) rename {learn => ..learn}/governance/overview.md (93%) rename {learn => ..learn}/transfers/cctp.md (87%) rename {learn => ..learn}/transfers/index.md (100%) rename {learn => ..learn}/transfers/native-token-transfers/deployment.md (100%) rename {learn => ..learn}/transfers/native-token-transfers/overview.md (93%) rename {learn => ..learn}/transfers/settlement/overview.md (96%) rename {learn => ..learn}/transfers/token-bridge.md (73%) rename .snippets/code/{tutorials/typescript-sdk/usdc-via-cctp => products/cctp-bridge/tutorials/complete-usdc-transfer}/cctp-sdk-1.ts (100%) rename .snippets/code/{tutorials/typescript-sdk/usdc-via-cctp => products/cctp-bridge/tutorials/complete-usdc-transfer}/cctp-sdk-2.ts (100%) rename .snippets/code/{tutorials/typescript-sdk/usdc-via-cctp => products/cctp-bridge/tutorials/complete-usdc-transfer}/cctp-sdk-3.ts (100%) rename .snippets/code/{tutorials/typescript-sdk/usdc-via-cctp => products/cctp-bridge/tutorials/complete-usdc-transfer}/cctp-sdk-4.ts (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/advanced-configuration.json (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/arbitrary-token.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/configure-html.html (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/configure-react-v0.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/custom-full.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/custom-simple-testnet-v0.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/custom-simple-v0.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/index.ts (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/configuration-v0}/sample-configuration.json (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/add-token.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/configure-hosted.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/configure-react-v1.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-coingecko-key.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-disable-arbitrary-tokens.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-simple-testnet-v1.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-simple-v1.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-tokens-whitelist-advanced.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-tokens-whitelist.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/custom-tx-settings-solana.jsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/example-all-routes.ts (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/data}/example-cctp.ts (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/theme}/custom-colors-hosted.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/theme}/custom-colors.tsx (100%) rename .snippets/code/{build/transfers/connect/configuration => products/connect/configuration/theme}/custom-menu.jsx (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/receiveEmitterCheck.ts (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/receiveMessageEVM.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/receiveMessageSolana.rs (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/receiving.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/sendMessageEVM.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/sendMessageSolana.rs (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/core-contracts/sending.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/wormhole-relayers/ExampleContract.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/wormhole-relayers/getQuoteAndSend.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/wormhole-relayers/quoteEVMDeliveryPrice.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/wormhole-relayers/receiveWormholeMessages.sol (100%) rename .snippets/code/{build/core-messaging => products/messaging/guides}/wormhole-relayers/sendPayloadToEvm.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-1.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-2.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-3.ts (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-4.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-5.ts (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-6.ts (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-7.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-8.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts/snippet-9.json (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-1.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-10.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-11.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-2.sol (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-3.json (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-4.ts (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-5.ts (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-6.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-7.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-8.html (100%) rename .snippets/code/{tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-transfers/snippet-9.json (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-1.json (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-10.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-11.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-12.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-13.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-14.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-15.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-16.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-17.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-2.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-3.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-4.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-5.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-6.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-7.ts (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-8.html (100%) rename .snippets/code/{tutorials/wormholescan => products/messaging/tutorials}/replace-signatures/replace-sigs-9.ts (100%) rename .snippets/code/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides/deploy-to-evm}/INttToken.sol (100%) rename .snippets/code/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides/deploy-to-evm}/initialize.txt (100%) rename .snippets/code/{build => products}/reference/formatted-addresses/evm.ts (100%) rename .snippets/code/{build => products}/reference/formatted-addresses/solana.ts (100%) rename .snippets/code/{build/transfers/settlement => products/settlement/guides/liquidity-layer}/placeFastMarketOrder.sol (100%) rename .snippets/code/{build/transfers/settlement => products/settlement/guides/liquidity-layer}/placeMarketOrder.sol (100%) rename .snippets/code/{build/transfers/settlement => products/settlement/guides/solver}/solver-config.json (100%) rename .snippets/code/{tutorials/typescript-sdk/tokens-via-token-bridge => products/token-bridge/tutorials/transfer-workflow}/token-bridge-1.ts (100%) rename .snippets/code/{tutorials/typescript-sdk/tokens-via-token-bridge => products/token-bridge/tutorials/transfer-workflow}/token-bridge-2.ts (100%) rename .snippets/code/{tutorials/typescript-sdk/tokens-via-token-bridge => products/token-bridge/tutorials/transfer-workflow}/token-bridge-3.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-1.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-2.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-3.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-4.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-5.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-6.ts (100%) rename .snippets/code/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/snippet-7.ts (100%) rename .snippets/code/{learn => protocol}/infrastructure/VAAs/snippet-1.js (100%) rename .snippets/code/{learn => protocol}/infrastructure/VAAs/snippet-2.js (100%) rename .snippets/code/{build/toolkit/solidity-sdk => tools/solidity-sdk/sdk-reference}/solidity-sdk-1.sol (100%) rename .snippets/code/{build/toolkit/solidity-sdk => tools/solidity-sdk/sdk-reference}/solidity-sdk-2.sol (100%) rename .snippets/code/{build/toolkit/solidity-sdk => tools/solidity-sdk/sdk-reference}/solidity-sdk-3.sol (100%) rename .snippets/code/{build/toolkit/solidity-sdk => tools/solidity-sdk/sdk-reference}/solidity-sdk-4.sol (100%) rename .snippets/code/{build/toolkit/solidity-sdk => tools/solidity-sdk/sdk-reference}/solidity-sdk-5.sol (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-1.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-2.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-3.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-4.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-5.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-6.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-7.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads/pl-8.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-0.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-1.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-10.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-11.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-12.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-13.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-14.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-15.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-16.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-17.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-18.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-19.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-2.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-20.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-21.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-22.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-23.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-25.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-26.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-27.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-3.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-4.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-5.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-6.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-7.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-8.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout/layout-9.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/vaas-protocols/solidity-sdk.sol (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/vaas-protocols/ts-sdk.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/addresses.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/cctp.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/config-override.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/config.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/custom-route.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/ethers.js (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/example-core-bridge.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/get-chain.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/get-vaa.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/router.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/signers.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/token-bridge-snippet.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/token-bridge.ts (100%) rename .snippets/code/{build/toolkit/typescript-sdk => tools/typescript-sdk/sdk-reference}/tokens.ts (100%) delete mode 100644 .snippets/text/learn/infrastructure/infrastructure-index-timeline.json rename .snippets/text/{build => products}/reference/chain-ids/chain-ids.md (100%) rename .snippets/text/{build => products}/reference/consistency-levels/consistency-levels.md (100%) rename .snippets/text/{build => products}/reference/contract-addresses/cctp.md (100%) rename .snippets/text/{build => products}/reference/contract-addresses/core-contracts.md (100%) rename .snippets/text/{build => products}/reference/contract-addresses/read-only.md (100%) rename .snippets/text/{build => products}/reference/contract-addresses/relayer.md (100%) rename .snippets/text/{build => products}/reference/contract-addresses/token-bridge.md (100%) rename .snippets/text/{build/start-building => products/reference}/testnet-faucets/testnet-faucets.md (100%) delete mode 100644 build/.pages delete mode 100644 build/core-messaging/.pages delete mode 100644 build/index.md delete mode 100644 build/infrastructure/.pages delete mode 100644 build/infrastructure/index.md delete mode 100644 build/infrastructure/relayers/.pages delete mode 100644 build/infrastructure/relayers/index.md delete mode 100644 build/infrastructure/spy/.pages delete mode 100644 build/infrastructure/spy/index.md delete mode 100644 build/multigov/.pages delete mode 100644 build/queries/.pages delete mode 100644 build/queries/index.md delete mode 100644 build/reference/.pages delete mode 100644 build/reference/index.md delete mode 100644 build/start-building/.pages delete mode 100644 build/start-building/index.md delete mode 100644 build/toolkit/.pages delete mode 100644 build/toolkit/index.md delete mode 100644 build/toolkit/typescript-sdk/index.md delete mode 100644 build/transfers/.pages delete mode 100644 build/transfers/connect/.pages delete mode 100644 build/transfers/connect/configuration/.pages delete mode 100644 build/transfers/connect/configuration/index.md delete mode 100644 build/transfers/index.md delete mode 100644 build/transfers/native-token-transfers/.pages delete mode 100644 build/transfers/native-token-transfers/configuration/.pages delete mode 100644 build/transfers/native-token-transfers/configuration/index.md delete mode 100644 build/transfers/native-token-transfers/deployment-process/.pages delete mode 100644 build/transfers/native-token-transfers/deployment-process/index.md delete mode 100644 build/transfers/settlement/.pages delete mode 100644 build/transfers/settlement/index.md rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-1.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-2.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-3.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-4.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-5.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-6.webp (100%) rename images/{tutorials/connect => products/connect/tutorials}/react-dapp/connect-7.webp (100%) rename images/{build/core-messaging => products/messaging}/wormhole-relayers/relayer-1.webp (100%) rename images/{learn/governance => products/multigov/concepts/architecture}/multigov-detailed.webp (100%) rename images/{learn/governance => products/multigov/concepts/architecture}/multigov-high-level.webp (100%) rename images/{learn/transfers/native-token-transfers => products/native-token-transfers/concepts}/architecture/architecture-1.webp (100%) rename images/{learn/transfers/native-token-transfers => products/native-token-transfers/concepts}/architecture/architecture-2.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-1.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-10.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-11.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-12.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-13.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-14.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-15.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-2.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-3.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-4.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-5.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-6.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-7.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-8.webp (100%) rename images/{build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad/ntt-launchpad-9.webp (100%) rename images/{learn/transfers/settlement => products/settlement/concepts}/architecture/architecture-1.webp (100%) rename images/{learn/transfers/settlement => products/settlement/concepts}/architecture/architecture-2.webp (100%) rename images/{learn/transfers/settlement => products/settlement/concepts}/architecture/architecture-3.webp (100%) rename images/{tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-tokens/multichain-token-1.webp (100%) rename images/{tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-tokens/multichain-token-2.webp (100%) rename images/{tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-tokens/multichain-token-3.webp (100%) rename images/{tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-tokens/multichain-token-4.webp (100%) rename images/{tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-tokens/multichain-token-5.webp (100%) rename images/{learn/infrastructure => protocol}/architecture/architecture-1.webp (100%) rename images/{build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer/relayer-1.webp (100%) rename images/{learn => protocol}/infrastructure/vaas/lifetime-vaa-diagram.webp (100%) rename images/{learn => protocol}/introduction/introduction-1.webp (100%) delete mode 100644 learn/.pages delete mode 100644 learn/governance/.pages delete mode 100644 learn/governance/faq.md delete mode 100644 learn/governance/index.md delete mode 100644 learn/index.md delete mode 100644 learn/infrastructure/.pages delete mode 100644 learn/infrastructure/index.md delete mode 100644 learn/transfers/.pages delete mode 100644 learn/transfers/native-token-transfers/.pages delete mode 100644 learn/transfers/native-token-transfers/index.md delete mode 100644 learn/transfers/settlement/.pages delete mode 100644 learn/transfers/settlement/index.md delete mode 100644 ntt/.pages delete mode 100644 ntt/architecture.md delete mode 100644 ntt/overview.md create mode 100644 products/.pages create mode 100644 products/cctp-bridge/.pages create mode 100644 products/cctp-bridge/concepts/.pages create mode 100644 products/cctp-bridge/concepts/integration.md create mode 100644 products/cctp-bridge/get-started.md create mode 100644 products/cctp-bridge/guides/.pages create mode 100644 products/cctp-bridge/guides/transfer-usdc.md create mode 100644 products/cctp-bridge/overview.md create mode 100644 products/cctp-bridge/tutorials/.pages rename tutorials/typescript-sdk/usdc-via-cctp.md => products/cctp-bridge/tutorials/complete-usdc-transfer.md (89%) create mode 100644 products/connect/.pages create mode 100644 products/connect/concepts/.pages rename {build/transfers/connect => products/connect/concepts}/routes.md (91%) create mode 100644 products/connect/configuration/.pages rename {build/transfers/connect => products/connect/configuration}/configuration-v0.md (93%) rename build/transfers/connect/configuration/configure-data.md => products/connect/configuration/data.md (89%) rename build/transfers/connect/configuration/configure-theme.md => products/connect/configuration/theme.md (93%) rename {build/transfers => products}/connect/faqs.md (92%) create mode 100644 products/connect/get-started.md create mode 100644 products/connect/guides/.pages rename {build/transfers/connect => products/connect/guides}/upgrade.md (98%) create mode 100644 products/connect/overview.md create mode 100644 products/connect/reference/.pages rename build/transfers/connect/features.md => products/connect/reference/support-matrix.md (97%) create mode 100644 products/connect/tutorials/.pages rename {tutorials/connect => products/connect/tutorials}/react-dapp.md (91%) create mode 100644 products/messaging/.pages create mode 100644 products/messaging/get-started.md create mode 100644 products/messaging/guides/.pages rename {build/core-messaging => products/messaging/guides}/core-contracts.md (83%) rename {build/core-messaging => products/messaging/guides}/wormhole-relayers.md (91%) create mode 100644 products/messaging/overview.md create mode 100644 products/messaging/tutorials/.pages rename {tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-contracts.md (83%) rename {tutorials/solidity-sdk => products/messaging/tutorials}/cross-chain-token-contracts.md (86%) rename {tutorials/wormholescan => products/messaging/tutorials}/replace-signatures.md (80%) create mode 100644 products/multigov/.pages create mode 100644 products/multigov/concepts/.pages rename {learn/governance => products/multigov/concepts}/architecture.md (98%) rename build/multigov/faq.md => products/multigov/faqs.md (71%) create mode 100644 products/multigov/get-started.md create mode 100644 products/multigov/guides/.pages rename {build/multigov => products/multigov/guides}/deploy-to-evm.md (98%) rename {build/multigov => products/multigov/guides}/deploy-to-solana.md (98%) rename {build/multigov => products/multigov/guides}/upgrade-evm.md (100%) rename {build/multigov => products/multigov/guides}/upgrade-solana.md (100%) create mode 100644 products/multigov/overview.md create mode 100644 products/multigov/tutorials/.pages rename {tutorials/multigov => products/multigov/tutorials}/treasury-proposal.md (100%) create mode 100644 products/native-token-transfers/.pages create mode 100644 products/native-token-transfers/concepts/.pages rename {learn/transfers/native-token-transfers => products/native-token-transfers/concepts}/architecture.md (96%) rename {learn/transfers/native-token-transfers => products/native-token-transfers/concepts}/security.md (100%) create mode 100644 products/native-token-transfers/configuration/.pages rename {build/transfers => products}/native-token-transfers/configuration/access-control.md (100%) rename {build/transfers => products}/native-token-transfers/configuration/rate-limiting.md (100%) rename {build/transfers => products}/native-token-transfers/faqs.md (95%) create mode 100644 products/native-token-transfers/get-started.md create mode 100644 products/native-token-transfers/guides/.pages rename {build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/deploy-to-evm.md (93%) rename {build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/deploy-to-solana.md (86%) rename {build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/evm-launchpad.md (73%) create mode 100644 products/native-token-transfers/overview.md create mode 100644 products/native-token-transfers/reference/.pages rename {build/transfers/native-token-transfers => products/native-token-transfers/reference}/cli-commands.md (92%) rename {build/transfers/native-token-transfers/deployment-process => products/native-token-transfers}/troubleshooting.md (87%) rename {build/start-building => products}/products.md (85%) create mode 100644 products/queries/.pages create mode 100644 products/queries/concepts/.pages create mode 100644 products/queries/concepts/rpc-basics.md rename {build => products}/queries/faqs.md (100%) create mode 100644 products/queries/get-started.md create mode 100644 products/queries/guides/.pages create mode 100644 products/queries/guides/construct-a-query.md create mode 100644 products/queries/guides/mock-a-query.md create mode 100644 products/queries/guides/query-request.md rename ntt/index.md => products/queries/guides/submit-response.md (100%) create mode 100644 products/queries/guides/verify-response.md create mode 100644 products/queries/overview.md create mode 100644 products/queries/reference/.pages create mode 100644 products/queries/reference/supported-methods.md create mode 100644 products/queries/reference/supported-networks.md create mode 100644 products/reference/.pages rename {build => products}/reference/chain-ids.md (91%) rename {build => products}/reference/consistency-levels.md (91%) rename {build => products}/reference/contract-addresses.md (68%) rename {build/start-building => products/reference}/supported-networks.md (100%) rename {build/start-building => products/reference}/testnet-faucets.md (87%) rename {build => products}/reference/wormhole-formatted-addresses.md (98%) create mode 100644 products/settlement/.pages create mode 100644 products/settlement/concepts/.pages rename {learn/transfers/settlement => products/settlement/concepts}/architecture.md (96%) rename {build/transfers => products}/settlement/faqs.md (100%) create mode 100644 products/settlement/get-started.md create mode 100644 products/settlement/guides/.pages rename {build/transfers/settlement => products/settlement/guides}/liquidity-layer.md (95%) rename {build/transfers/settlement => products/settlement/guides}/solver.md (99%) create mode 100644 products/settlement/overview.md rename {tutorials/settlement => products/settlement/tutorials}/.settlement-routes.md (98%) create mode 100644 products/token-bridge/.pages create mode 100644 products/token-bridge/concepts/.pages create mode 100644 products/token-bridge/concepts/payload-structure.md create mode 100644 products/token-bridge/concepts/transfer-flow.md create mode 100644 products/token-bridge/faqs.md create mode 100644 products/token-bridge/get-started.md create mode 100644 products/token-bridge/guides/.pages create mode 100644 products/token-bridge/guides/transfer-wrapped-assets.md create mode 100644 products/token-bridge/overview.md create mode 100644 products/token-bridge/tutorials/.pages rename {tutorials/multichain-assets => products/token-bridge/tutorials}/multichain-token.md (90%) rename tutorials/typescript-sdk/tokens-via-token-bridge.md => products/token-bridge/tutorials/transfer-workflow.md (84%) create mode 100644 protocol/.pages rename {learn/infrastructure => protocol}/architecture.md (66%) create mode 100644 protocol/infrastructure-guides/.pages rename {build/infrastructure/relayers => protocol/infrastructure-guides}/run-relayer.md (92%) rename {build/infrastructure/spy => protocol/infrastructure-guides}/run-spy.md (98%) create mode 100644 protocol/infrastructure/.pages rename {learn => protocol}/infrastructure/core-contracts.md (89%) rename {learn => protocol}/infrastructure/guardians.md (93%) rename {learn => protocol}/infrastructure/relayer.md (92%) rename {learn => protocol}/infrastructure/spy.md (95%) rename {learn => protocol}/infrastructure/vaas.md (95%) rename {learn => protocol}/introduction.md (87%) rename {learn => protocol}/security.md (94%) create mode 100644 tools/.pages create mode 100644 tools/solidity-sdk/.pages create mode 100644 tools/solidity-sdk/get-started.md rename build/toolkit/solidity-sdk.md => tools/solidity-sdk/sdk-reference.md (90%) create mode 100644 tools/typescript-sdk/.pages create mode 100644 tools/typescript-sdk/get-started.md rename {build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/.pages (67%) rename {build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/protocols-payloads.md (95%) rename {build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/sdk-layout.md (92%) rename {build/toolkit/typescript-sdk => tools/typescript-sdk/guides}/vaas-protocols.md (83%) rename build/toolkit/typescript-sdk/wormhole-sdk.md => tools/typescript-sdk/sdk-reference.md (91%) delete mode 100644 tutorials/.pages delete mode 100644 tutorials/connect/.pages delete mode 100644 tutorials/connect/index.md delete mode 100644 tutorials/index.md delete mode 100644 tutorials/multichain-assets/.pages delete mode 100644 tutorials/multichain-assets/index.md delete mode 100644 tutorials/multigov/.pages delete mode 100644 tutorials/multigov/index.md delete mode 100644 tutorials/settlement/.index.md delete mode 100644 tutorials/settlement/.pages delete mode 100644 tutorials/solidity-sdk/.pages delete mode 100644 tutorials/solidity-sdk/index.md delete mode 100644 tutorials/typescript-sdk/.pages delete mode 100644 tutorials/typescript-sdk/index.md delete mode 100644 tutorials/wormholescan/.pages delete mode 100644 tutorials/wormholescan/index.md diff --git a/build/core-messaging/index.md b/..build/core-messaging/index.md similarity index 81% rename from build/core-messaging/index.md rename to ..build/core-messaging/index.md index 254753fdb..bfaa5a14e 100644 --- a/build/core-messaging/index.md +++ b/..build/core-messaging/index.md @@ -12,7 +12,7 @@ Follow the links below for how-to guides about using Core Contracts and Wormhole ## Simplified Message Flow -Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/build/start-building/supported-networks/){target=\_blank} page. +Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. [timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] @@ -26,7 +26,7 @@ Wormhole-deployed relayer support is limited to EVM environments. For a complete Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. - [:custom-arrow: Get started](/docs/build/core-messaging/core-contracts/#prerequisites) + [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) - :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** @@ -34,6 +34,6 @@ Wormhole-deployed relayer support is limited to EVM environments. For a complete Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. - [:custom-arrow: Get started](/docs/build/core-messaging/wormhole-relayers/#get-started-with-the-wormhole-relayer) + [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) diff --git a/build/multigov/index.md b/..build/multigov/index.md similarity index 90% rename from build/multigov/index.md rename to ..build/multigov/index.md index b3e63e33b..0a40adf15 100644 --- a/build/multigov/index.md +++ b/..build/multigov/index.md @@ -25,7 +25,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -33,7 +33,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** @@ -41,7 +41,7 @@ Take the following steps to get started with a MultiGov integration: Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/build/multigov/upgrade-evm/) + [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** @@ -49,7 +49,7 @@ Take the following steps to get started with a MultiGov integration: Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/build/multigov/upgrade-solana/) + [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - :octicons-question-16:{ .lg .middle } **Technical FAQs** @@ -57,7 +57,7 @@ Take the following steps to get started with a MultiGov integration: Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) diff --git a/build/queries/overview.md b/..build/queries/overview.md similarity index 98% rename from build/queries/overview.md rename to ..build/queries/overview.md index 40c19d82d..2b532bf6b 100644 --- a/build/queries/overview.md +++ b/..build/queries/overview.md @@ -90,7 +90,7 @@ For example, many chains have implementations forked from [Geth](https://github. Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. -Be sure to check out the [FAQs](/docs/build/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. +Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. You can also check out the following examples of applications that make use of Wormhole Queries: diff --git a/build/queries/use-queries.md b/..build/queries/use-queries.md similarity index 98% rename from build/queries/use-queries.md rename to ..build/queries/use-queries.md index 788463103..0a5ebcdb4 100644 --- a/build/queries/use-queries.md +++ b/..build/queries/use-queries.md @@ -120,7 +120,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe diff --git a/build/start-building/use-cases.md b/..build/start-building/use-cases.md similarity index 75% rename from build/start-building/use-cases.md rename to ..build/start-building/use-cases.md index fd0b89698..f1ecdbd64 100644 --- a/build/start-building/use-cases.md +++ b/..build/start-building/use-cases.md @@ -18,8 +18,8 @@ Enable seamless swaps between chains with real-time liquidity routing. 🛠 **Wormhole products used:** -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution 🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} @@ -40,8 +40,8 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time 🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} @@ -63,7 +63,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -83,7 +83,7 @@ Enable direct BTC transfers without wrapped assets. 🛠 **Wormhole products used:** -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains 🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} @@ -102,7 +102,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -123,8 +123,8 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -165,8 +165,8 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -186,7 +186,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -228,8 +228,8 @@ Allow merchants and platforms to accept payments in any token, auto-converting t 🛠 **Wormhole products used:** -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers 🔗 **Used in:** E-commerce, Web3 payments, and subscription models @@ -250,7 +250,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -270,8 +270,8 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} diff --git a/build/toolkit/cli.md b/..build/toolkit/cli.md similarity index 100% rename from build/toolkit/cli.md rename to ..build/toolkit/cli.md diff --git a/build/toolkit/dev-env.md b/..build/toolkit/dev-env.md similarity index 81% rename from build/toolkit/dev-env.md rename to ..build/toolkit/dev-env.md index 983c286f2..2a4703ed8 100644 --- a/build/toolkit/dev-env.md +++ b/..build/toolkit/dev-env.md @@ -10,7 +10,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/build/start-building/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -28,7 +28,7 @@ Relying on native tools when possible allows for more rapid prototyping and iter ### Integration -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/build/start-building/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. !!! note Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. @@ -46,7 +46,7 @@ If you'd like to set up a local validator environment, follow the setup guide fo ### Testnet -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: ```text https://api.testnet.wormholescan.io @@ -54,7 +54,7 @@ https://api.testnet.wormholescan.io ### Mainnet -The Mainnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: ```text https://api.wormholescan.io diff --git a/build/toolkit/faqs.md b/..build/toolkit/faqs.md similarity index 96% rename from build/toolkit/faqs.md rename to ..build/toolkit/faqs.md index 09f7227ff..3623af556 100644 --- a/build/toolkit/faqs.md +++ b/..build/toolkit/faqs.md @@ -46,7 +46,7 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo 3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/build/reference/contract-addresses/){target=\_blank} section + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field diff --git a/build/transfers/cctp.md b/..build/transfers/cctp.md similarity index 98% rename from build/transfers/cctp.md rename to ..build/transfers/cctp.md index ac38445ab..3acdb9576 100644 --- a/build/transfers/cctp.md +++ b/..build/transfers/cctp.md @@ -18,8 +18,8 @@ This guide will walk you through getting started with Wormhole's CCTP contracts To interact with the Wormhole CCTP, you'll need the following: -- [The address of the CCTP contract](/docs/build/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on ## Wormhole's CCTP Integration Contract @@ -30,7 +30,7 @@ The Circle Integration contract emits Wormhole messages with arbitrary payloads This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. !!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/build/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. ??? code "Circle Integration contract" ```solidity diff --git a/build/transfers/connect/index.md b/..build/transfers/connect/index.md similarity index 87% rename from build/transfers/connect/index.md rename to ..build/transfers/connect/index.md index 93e314c44..b53eb233d 100644 --- a/build/transfers/connect/index.md +++ b/..build/transfers/connect/index.md @@ -38,10 +38,10 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag --- - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/build/start-building/supported-networks/){target=\_blank}. + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - [:custom-arrow: Get started](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - :octicons-tools-16:{ .lg .middle } **Connect FAQs** @@ -50,7 +50,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [:custom-arrow: Visit FAQs](/docs/build/transfers/connect/faqs/) + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** @@ -58,7 +58,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - [:custom-arrow: Supported Features](/docs/build/transfers/connect/features/) + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) diff --git a/build/transfers/connect/overview.md b/..build/transfers/connect/overview.md similarity index 82% rename from build/transfers/connect/overview.md rename to ..build/transfers/connect/overview.md index bfadf259a..1d1a585d5 100644 --- a/build/transfers/connect/overview.md +++ b/..build/transfers/connect/overview.md @@ -16,13 +16,13 @@ The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-d Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -- Multiple ways to bridge assets ([routes](/docs/build/transfers/connect/routes/){target=\_blank}) +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) - Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer +- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer - Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/build/transfers/connect/features/){target=\_blank} at the destination +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/build/transfers/connect/features/){target=\_blank}. +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## Integrate Connect {: #integrate-connect } @@ -48,7 +48,7 @@ If you're not using React, you can still embed Connect on your website by using --8<-- 'code/build/transfers/connect/overview/hosted.js' ``` -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/build/transfers/connect/upgrade/){target=\_blank} guide. +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. ???- code "v0.x" Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. @@ -67,7 +67,7 @@ It is important to periodically update your Wormhole Connect instance to the lat ## Configuration {: #configuration} -This is just an overview of what's possible. Check the [Configuration docs](/docs/build/transfers/connect/configuration/){target=\_blank} for details about all the configuration options. +This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: @@ -75,6 +75,6 @@ The default configuration of Wormhole Connect may not be exactly what you're loo - Restrict the chains that you allow in your app - Add support for your project's token, and eliminate tokens you don't want to reduce noise - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/build/transfers/connect/routes/){target=\_blank} that are available + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available -For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. +For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. diff --git a/build/transfers/native-token-transfers/deployment-process/installation.md b/..build/transfers/native-token-transfers/deployment-process/installation.md similarity index 90% rename from build/transfers/native-token-transfers/deployment-process/installation.md rename to ..build/transfers/native-token-transfers/deployment-process/installation.md index 389c43327..cc1aa8d33 100644 --- a/build/transfers/native-token-transfers/deployment-process/installation.md +++ b/..build/transfers/native-token-transfers/deployment-process/installation.md @@ -32,7 +32,7 @@ Follow these steps to install the NTT CLI: ntt --version ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/){target=\_blank} to start using the CLI +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI ## Update NTT CLI @@ -70,7 +70,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to EVM chains](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-tools-16:{ .lg .middle } **Deploy to Solana** @@ -78,6 +78,6 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to Solana](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) diff --git a/build/transfers/native-token-transfers/deployment-process/post-deployment.md b/..build/transfers/native-token-transfers/deployment-process/post-deployment.md similarity index 90% rename from build/transfers/native-token-transfers/deployment-process/post-deployment.md rename to ..build/transfers/native-token-transfers/deployment-process/post-deployment.md index c451d8854..3dfa78984 100644 --- a/build/transfers/native-token-transfers/deployment-process/post-deployment.md +++ b/..build/transfers/native-token-transfers/deployment-process/post-deployment.md @@ -10,8 +10,8 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} allows for a direct integration into your infrastructure +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment diff --git a/build/transfers/native-token-transfers/index.md b/..build/transfers/native-token-transfers/index.md similarity index 84% rename from build/transfers/native-token-transfers/index.md rename to ..build/transfers/native-token-transfers/index.md index 360c38107..2abe026fb 100644 --- a/build/transfers/native-token-transfers/index.md +++ b/..build/transfers/native-token-transfers/index.md @@ -22,7 +22,7 @@ The process for creating, deploying, and monitoring NTTs is as follows. Select t If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. ## Additional Resources @@ -34,7 +34,7 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - [:custom-arrow: NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/) + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - :octicons-question-16:{ .lg .middle } **NTT FAQs** @@ -42,6 +42,6 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) diff --git a/build/transfers/native-token-transfers/managers-transceivers.md b/..build/transfers/native-token-transfers/managers-transceivers.md similarity index 100% rename from build/transfers/native-token-transfers/managers-transceivers.md rename to ..build/transfers/native-token-transfers/managers-transceivers.md diff --git a/build/transfers/token-bridge.md b/..build/transfers/token-bridge.md similarity index 71% rename from build/transfers/token-bridge.md rename to ..build/transfers/token-bridge.md index 350125143..b4eb849a5 100644 --- a/build/transfers/token-bridge.md +++ b/..build/transfers/token-bridge.md @@ -8,7 +8,7 @@ categories: Token-Bridge, Transfer ## Introduction -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. @@ -16,8 +16,8 @@ This page outlines the core contract methods needed to integrate Token Bridge fu To interact with the Wormhole Token Bridge, you'll need the following: -- [The address of the Token Bridge contract](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers ## How to Interact with Token Bridge Contracts @@ -216,34 +216,3 @@ For a deeper understanding of the Token Bridge implementation and to review the ## Portal Bridge A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. - -## FAQs - -### Can ownership of wrapped tokens be transferred from the Token Bridge? - -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - - - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge - -The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. - -Relevant contracts: - - - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} - - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} - -### How do I update the metadata of a wrapped token? - -Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. - -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? - -You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. - -### How can I update my wrapped token image on Solscan? - -Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. - -To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. diff --git a/learn/glossary.md b/..learn/glossary.md similarity index 82% rename from learn/glossary.md rename to ..learn/glossary.md index 0f06b1012..b87ee819f 100644 --- a/learn/glossary.md +++ b/..learn/glossary.md @@ -12,11 +12,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -32,7 +32,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -66,7 +66,7 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator diff --git a/learn/governance/overview.md b/..learn/governance/overview.md similarity index 93% rename from learn/governance/overview.md rename to ..learn/governance/overview.md index 365003117..594047b0f 100644 --- a/learn/governance/overview.md +++ b/..learn/governance/overview.md @@ -32,7 +32,7 @@ MultiGov is important because it: The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/learn/governance/architecture/){target=\_blank} page. +For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/learn/governance/multigov-high-level.webp) +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) diff --git a/learn/transfers/cctp.md b/..learn/transfers/cctp.md similarity index 87% rename from learn/transfers/cctp.md rename to ..learn/transfers/cctp.md index 865bdbed8..9d3ccad5d 100644 --- a/learn/transfers/cctp.md +++ b/..learn/transfers/cctp.md @@ -17,13 +17,13 @@ While this protocol is wholly separate from Wormhole itself, Wormhole builds on !!! note Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} directly. +You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. ## Automatic Relaying To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank}. +This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. diff --git a/learn/transfers/index.md b/..learn/transfers/index.md similarity index 100% rename from learn/transfers/index.md rename to ..learn/transfers/index.md diff --git a/learn/transfers/native-token-transfers/deployment.md b/..learn/transfers/native-token-transfers/deployment.md similarity index 100% rename from learn/transfers/native-token-transfers/deployment.md rename to ..learn/transfers/native-token-transfers/deployment.md diff --git a/learn/transfers/native-token-transfers/overview.md b/..learn/transfers/native-token-transfers/overview.md similarity index 93% rename from learn/transfers/native-token-transfers/overview.md rename to ..learn/transfers/native-token-transfers/overview.md index 2107377ae..033d3fae2 100644 --- a/learn/transfers/native-token-transfers/overview.md +++ b/..learn/transfers/native-token-transfers/overview.md @@ -9,8 +9,8 @@ categories: NTT, Transfer !!!tip "Looking to deploy NTT?" If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/){target=\_blank} + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} ## Introduction @@ -57,12 +57,12 @@ The Token Bridge offers a secure, low-effort integration suitable for applicatio - **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract - **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/learn/security/){target=\_blank} +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} - **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process - **Integration** - straightforward and permissionless method to deploy on multiple chains !!! note - [Learn more](/docs/learn/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. ## Supported Token Standards diff --git a/learn/transfers/settlement/overview.md b/..learn/transfers/settlement/overview.md similarity index 96% rename from learn/transfers/settlement/overview.md rename to ..learn/transfers/settlement/overview.md index c3e3614a8..a5807d7a7 100644 --- a/learn/transfers/settlement/overview.md +++ b/..learn/transfers/settlement/overview.md @@ -41,4 +41,4 @@ Due to the hub-spoke model of liquidity, new chains without proven traction can ## Related Resources -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/learn/transfers/settlement/architecture/){target=\_blank} page \ No newline at end of file +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page \ No newline at end of file diff --git a/learn/transfers/token-bridge.md b/..learn/transfers/token-bridge.md similarity index 73% rename from learn/transfers/token-bridge.md rename to ..learn/transfers/token-bridge.md index 31be693b5..4da83ce04 100644 --- a/learn/transfers/token-bridge.md +++ b/..learn/transfers/token-bridge.md @@ -10,19 +10,19 @@ Transferring tokens across blockchain networks is challenging due to the lack of Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. ### How Does It Work? -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/learn/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/learn/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. -While the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). ### Token Transfer Flow @@ -59,7 +59,7 @@ One of the key challenges in cross-chain token transfers is maintaining the corr The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. -The [Wormhole Guardian Network](/docs/learn/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. ### Portal Bridge diff --git a/.gitignore b/.gitignore index e351df955..e38d6695f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -scripts/__pycache__/* \ No newline at end of file +scripts/__pycache__/* +**/.DS_Store diff --git a/.pages b/.pages index befd97afb..11733efcd 100644 --- a/.pages +++ b/.pages @@ -1,7 +1,5 @@ nav: - - index.md - - build - - tutorials - - learn - - 'AI Resources': ai-resources.md - - ntt \ No newline at end of file +- products +- protocol +- 'AI Resources': ai-resources.md +# - tools \ No newline at end of file diff --git a/.snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-1.ts b/.snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-1.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-1.ts rename to .snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-1.ts diff --git a/.snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts b/.snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts rename to .snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts diff --git a/.snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts b/.snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts rename to .snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts diff --git a/.snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-4.ts b/.snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-4.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-4.ts rename to .snippets/code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-4.ts diff --git a/.snippets/code/build/transfers/connect/configuration/advanced-configuration.json b/.snippets/code/products/connect/configuration/configuration-v0/advanced-configuration.json similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/advanced-configuration.json rename to .snippets/code/products/connect/configuration/configuration-v0/advanced-configuration.json diff --git a/.snippets/code/build/transfers/connect/configuration/arbitrary-token.tsx b/.snippets/code/products/connect/configuration/configuration-v0/arbitrary-token.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/arbitrary-token.tsx rename to .snippets/code/products/connect/configuration/configuration-v0/arbitrary-token.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/configure-html.html b/.snippets/code/products/connect/configuration/configuration-v0/configure-html.html similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/configure-html.html rename to .snippets/code/products/connect/configuration/configuration-v0/configure-html.html diff --git a/.snippets/code/build/transfers/connect/configuration/configure-react-v0.tsx b/.snippets/code/products/connect/configuration/configuration-v0/configure-react-v0.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/configure-react-v0.tsx rename to .snippets/code/products/connect/configuration/configuration-v0/configure-react-v0.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-full.jsx b/.snippets/code/products/connect/configuration/configuration-v0/custom-full.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-full.jsx rename to .snippets/code/products/connect/configuration/configuration-v0/custom-full.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-simple-testnet-v0.tsx b/.snippets/code/products/connect/configuration/configuration-v0/custom-simple-testnet-v0.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-simple-testnet-v0.tsx rename to .snippets/code/products/connect/configuration/configuration-v0/custom-simple-testnet-v0.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-simple-v0.jsx b/.snippets/code/products/connect/configuration/configuration-v0/custom-simple-v0.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-simple-v0.jsx rename to .snippets/code/products/connect/configuration/configuration-v0/custom-simple-v0.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/index.ts b/.snippets/code/products/connect/configuration/configuration-v0/index.ts similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/index.ts rename to .snippets/code/products/connect/configuration/configuration-v0/index.ts diff --git a/.snippets/code/build/transfers/connect/configuration/sample-configuration.json b/.snippets/code/products/connect/configuration/configuration-v0/sample-configuration.json similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/sample-configuration.json rename to .snippets/code/products/connect/configuration/configuration-v0/sample-configuration.json diff --git a/.snippets/code/build/transfers/connect/configuration/add-token.tsx b/.snippets/code/products/connect/configuration/data/add-token.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/add-token.tsx rename to .snippets/code/products/connect/configuration/data/add-token.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/configure-hosted.tsx b/.snippets/code/products/connect/configuration/data/configure-hosted.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/configure-hosted.tsx rename to .snippets/code/products/connect/configuration/data/configure-hosted.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/configure-react-v1.tsx b/.snippets/code/products/connect/configuration/data/configure-react-v1.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/configure-react-v1.tsx rename to .snippets/code/products/connect/configuration/data/configure-react-v1.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-coingecko-key.jsx b/.snippets/code/products/connect/configuration/data/custom-coingecko-key.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-coingecko-key.jsx rename to .snippets/code/products/connect/configuration/data/custom-coingecko-key.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-disable-arbitrary-tokens.jsx b/.snippets/code/products/connect/configuration/data/custom-disable-arbitrary-tokens.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-disable-arbitrary-tokens.jsx rename to .snippets/code/products/connect/configuration/data/custom-disable-arbitrary-tokens.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-simple-testnet-v1.jsx b/.snippets/code/products/connect/configuration/data/custom-simple-testnet-v1.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-simple-testnet-v1.jsx rename to .snippets/code/products/connect/configuration/data/custom-simple-testnet-v1.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-simple-v1.jsx b/.snippets/code/products/connect/configuration/data/custom-simple-v1.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-simple-v1.jsx rename to .snippets/code/products/connect/configuration/data/custom-simple-v1.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-tokens-whitelist-advanced.jsx b/.snippets/code/products/connect/configuration/data/custom-tokens-whitelist-advanced.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-tokens-whitelist-advanced.jsx rename to .snippets/code/products/connect/configuration/data/custom-tokens-whitelist-advanced.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-tokens-whitelist.jsx b/.snippets/code/products/connect/configuration/data/custom-tokens-whitelist.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-tokens-whitelist.jsx rename to .snippets/code/products/connect/configuration/data/custom-tokens-whitelist.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-tx-settings-solana.jsx b/.snippets/code/products/connect/configuration/data/custom-tx-settings-solana.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-tx-settings-solana.jsx rename to .snippets/code/products/connect/configuration/data/custom-tx-settings-solana.jsx diff --git a/.snippets/code/build/transfers/connect/configuration/example-all-routes.ts b/.snippets/code/products/connect/configuration/data/example-all-routes.ts similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/example-all-routes.ts rename to .snippets/code/products/connect/configuration/data/example-all-routes.ts diff --git a/.snippets/code/build/transfers/connect/configuration/example-cctp.ts b/.snippets/code/products/connect/configuration/data/example-cctp.ts similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/example-cctp.ts rename to .snippets/code/products/connect/configuration/data/example-cctp.ts diff --git a/.snippets/code/build/transfers/connect/configuration/custom-colors-hosted.tsx b/.snippets/code/products/connect/configuration/theme/custom-colors-hosted.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-colors-hosted.tsx rename to .snippets/code/products/connect/configuration/theme/custom-colors-hosted.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-colors.tsx b/.snippets/code/products/connect/configuration/theme/custom-colors.tsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-colors.tsx rename to .snippets/code/products/connect/configuration/theme/custom-colors.tsx diff --git a/.snippets/code/build/transfers/connect/configuration/custom-menu.jsx b/.snippets/code/products/connect/configuration/theme/custom-menu.jsx similarity index 100% rename from .snippets/code/build/transfers/connect/configuration/custom-menu.jsx rename to .snippets/code/products/connect/configuration/theme/custom-menu.jsx diff --git a/.snippets/code/build/core-messaging/core-contracts/receiveEmitterCheck.ts b/.snippets/code/products/messaging/guides/core-contracts/receiveEmitterCheck.ts similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/receiveEmitterCheck.ts rename to .snippets/code/products/messaging/guides/core-contracts/receiveEmitterCheck.ts diff --git a/.snippets/code/build/core-messaging/core-contracts/receiveMessageEVM.sol b/.snippets/code/products/messaging/guides/core-contracts/receiveMessageEVM.sol similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/receiveMessageEVM.sol rename to .snippets/code/products/messaging/guides/core-contracts/receiveMessageEVM.sol diff --git a/.snippets/code/build/core-messaging/core-contracts/receiveMessageSolana.rs b/.snippets/code/products/messaging/guides/core-contracts/receiveMessageSolana.rs similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/receiveMessageSolana.rs rename to .snippets/code/products/messaging/guides/core-contracts/receiveMessageSolana.rs diff --git a/.snippets/code/build/core-messaging/core-contracts/receiving.sol b/.snippets/code/products/messaging/guides/core-contracts/receiving.sol similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/receiving.sol rename to .snippets/code/products/messaging/guides/core-contracts/receiving.sol diff --git a/.snippets/code/build/core-messaging/core-contracts/sendMessageEVM.sol b/.snippets/code/products/messaging/guides/core-contracts/sendMessageEVM.sol similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/sendMessageEVM.sol rename to .snippets/code/products/messaging/guides/core-contracts/sendMessageEVM.sol diff --git a/.snippets/code/build/core-messaging/core-contracts/sendMessageSolana.rs b/.snippets/code/products/messaging/guides/core-contracts/sendMessageSolana.rs similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/sendMessageSolana.rs rename to .snippets/code/products/messaging/guides/core-contracts/sendMessageSolana.rs diff --git a/.snippets/code/build/core-messaging/core-contracts/sending.sol b/.snippets/code/products/messaging/guides/core-contracts/sending.sol similarity index 100% rename from .snippets/code/build/core-messaging/core-contracts/sending.sol rename to .snippets/code/products/messaging/guides/core-contracts/sending.sol diff --git a/.snippets/code/build/core-messaging/wormhole-relayers/ExampleContract.sol b/.snippets/code/products/messaging/guides/wormhole-relayers/ExampleContract.sol similarity index 100% rename from .snippets/code/build/core-messaging/wormhole-relayers/ExampleContract.sol rename to .snippets/code/products/messaging/guides/wormhole-relayers/ExampleContract.sol diff --git a/.snippets/code/build/core-messaging/wormhole-relayers/getQuoteAndSend.sol b/.snippets/code/products/messaging/guides/wormhole-relayers/getQuoteAndSend.sol similarity index 100% rename from .snippets/code/build/core-messaging/wormhole-relayers/getQuoteAndSend.sol rename to .snippets/code/products/messaging/guides/wormhole-relayers/getQuoteAndSend.sol diff --git a/.snippets/code/build/core-messaging/wormhole-relayers/quoteEVMDeliveryPrice.sol b/.snippets/code/products/messaging/guides/wormhole-relayers/quoteEVMDeliveryPrice.sol similarity index 100% rename from .snippets/code/build/core-messaging/wormhole-relayers/quoteEVMDeliveryPrice.sol rename to .snippets/code/products/messaging/guides/wormhole-relayers/quoteEVMDeliveryPrice.sol diff --git a/.snippets/code/build/core-messaging/wormhole-relayers/receiveWormholeMessages.sol b/.snippets/code/products/messaging/guides/wormhole-relayers/receiveWormholeMessages.sol similarity index 100% rename from .snippets/code/build/core-messaging/wormhole-relayers/receiveWormholeMessages.sol rename to .snippets/code/products/messaging/guides/wormhole-relayers/receiveWormholeMessages.sol diff --git a/.snippets/code/build/core-messaging/wormhole-relayers/sendPayloadToEvm.sol b/.snippets/code/products/messaging/guides/wormhole-relayers/sendPayloadToEvm.sol similarity index 100% rename from .snippets/code/build/core-messaging/wormhole-relayers/sendPayloadToEvm.sol rename to .snippets/code/products/messaging/guides/wormhole-relayers/sendPayloadToEvm.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-1.sol b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-1.sol similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-1.sol rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-1.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-4.html b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-4.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-4.html rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-4.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-7.html b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-7.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-7.html rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-7.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-8.html b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-8.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-8.html rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-8.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-9.json b/.snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-9.json similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-contracts/snippet-9.json rename to .snippets/code/products/messaging/tutorials/cross-chain-contracts/snippet-9.json diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-10.html b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-10.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-10.html rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-10.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-11.sol b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-11.sol similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-11.sol rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-11.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-3.json b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-3.json similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-3.json rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-3.json diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-6.html b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-6.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-6.html rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-6.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-7.html b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-7.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-7.html rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-7.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-8.html b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-8.html similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-8.html rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-8.html diff --git a/.snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-9.json b/.snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-9.json similarity index 100% rename from .snippets/code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-9.json rename to .snippets/code/products/messaging/tutorials/cross-chain-token-transfers/snippet-9.json diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-1.json b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-1.json similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-1.json rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-1.json diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-10.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-10.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-10.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-10.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-11.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-11.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-11.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-11.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-12.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-12.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-12.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-12.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-13.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-13.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-13.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-13.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-14.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-14.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-14.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-14.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-15.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-15.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-15.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-15.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-16.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-16.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-16.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-16.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-17.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-17.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-17.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-17.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-2.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-2.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-2.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-2.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-3.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-3.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-3.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-3.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-5.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-5.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-5.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-5.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-6.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-6.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-6.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-6.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-7.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-7.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-7.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-7.ts diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-8.html b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-8.html similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-8.html rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-8.html diff --git a/.snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-9.ts b/.snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-9.ts similarity index 100% rename from .snippets/code/tutorials/wormholescan/replace-signatures/replace-sigs-9.ts rename to .snippets/code/products/messaging/tutorials/replace-signatures/replace-sigs-9.ts diff --git a/.snippets/code/build/transfers/native-token-transfers/deployment-process/INttToken.sol b/.snippets/code/products/native-token-transfers/guides/deploy-to-evm/INttToken.sol similarity index 100% rename from .snippets/code/build/transfers/native-token-transfers/deployment-process/INttToken.sol rename to .snippets/code/products/native-token-transfers/guides/deploy-to-evm/INttToken.sol diff --git a/.snippets/code/build/transfers/native-token-transfers/deployment-process/initialize.txt b/.snippets/code/products/native-token-transfers/guides/deploy-to-evm/initialize.txt similarity index 100% rename from .snippets/code/build/transfers/native-token-transfers/deployment-process/initialize.txt rename to .snippets/code/products/native-token-transfers/guides/deploy-to-evm/initialize.txt diff --git a/.snippets/code/build/reference/formatted-addresses/evm.ts b/.snippets/code/products/reference/formatted-addresses/evm.ts similarity index 100% rename from .snippets/code/build/reference/formatted-addresses/evm.ts rename to .snippets/code/products/reference/formatted-addresses/evm.ts diff --git a/.snippets/code/build/reference/formatted-addresses/solana.ts b/.snippets/code/products/reference/formatted-addresses/solana.ts similarity index 100% rename from .snippets/code/build/reference/formatted-addresses/solana.ts rename to .snippets/code/products/reference/formatted-addresses/solana.ts diff --git a/.snippets/code/build/transfers/settlement/placeFastMarketOrder.sol b/.snippets/code/products/settlement/guides/liquidity-layer/placeFastMarketOrder.sol similarity index 100% rename from .snippets/code/build/transfers/settlement/placeFastMarketOrder.sol rename to .snippets/code/products/settlement/guides/liquidity-layer/placeFastMarketOrder.sol diff --git a/.snippets/code/build/transfers/settlement/placeMarketOrder.sol b/.snippets/code/products/settlement/guides/liquidity-layer/placeMarketOrder.sol similarity index 100% rename from .snippets/code/build/transfers/settlement/placeMarketOrder.sol rename to .snippets/code/products/settlement/guides/liquidity-layer/placeMarketOrder.sol diff --git a/.snippets/code/build/transfers/settlement/solver-config.json b/.snippets/code/products/settlement/guides/solver/solver-config.json similarity index 100% rename from .snippets/code/build/transfers/settlement/solver-config.json rename to .snippets/code/products/settlement/guides/solver/solver-config.json diff --git a/.snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-1.ts b/.snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-1.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-1.ts rename to .snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-1.ts diff --git a/.snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts b/.snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts rename to .snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts diff --git a/.snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts b/.snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts similarity index 100% rename from .snippets/code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts rename to .snippets/code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-1.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-1.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-1.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-1.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-2.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-2.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-2.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-2.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-3.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-3.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-3.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-3.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-4.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-4.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-4.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-4.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-5.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-5.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-5.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-5.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-6.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-6.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-6.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-6.ts diff --git a/.snippets/code/build/infrastructure/relayers/run-relayer/snippet-7.ts b/.snippets/code/protocol/infrastructure-guides/run-relayer/snippet-7.ts similarity index 100% rename from .snippets/code/build/infrastructure/relayers/run-relayer/snippet-7.ts rename to .snippets/code/protocol/infrastructure-guides/run-relayer/snippet-7.ts diff --git a/.snippets/code/learn/infrastructure/VAAs/snippet-1.js b/.snippets/code/protocol/infrastructure/VAAs/snippet-1.js similarity index 100% rename from .snippets/code/learn/infrastructure/VAAs/snippet-1.js rename to .snippets/code/protocol/infrastructure/VAAs/snippet-1.js diff --git a/.snippets/code/learn/infrastructure/VAAs/snippet-2.js b/.snippets/code/protocol/infrastructure/VAAs/snippet-2.js similarity index 100% rename from .snippets/code/learn/infrastructure/VAAs/snippet-2.js rename to .snippets/code/protocol/infrastructure/VAAs/snippet-2.js diff --git a/.snippets/code/build/toolkit/solidity-sdk/solidity-sdk-1.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol similarity index 100% rename from .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-1.sol rename to .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol diff --git a/.snippets/code/build/toolkit/solidity-sdk/solidity-sdk-2.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol similarity index 100% rename from .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-2.sol rename to .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol diff --git a/.snippets/code/build/toolkit/solidity-sdk/solidity-sdk-3.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol similarity index 100% rename from .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-3.sol rename to .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol diff --git a/.snippets/code/build/toolkit/solidity-sdk/solidity-sdk-4.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol similarity index 100% rename from .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-4.sol rename to .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol diff --git a/.snippets/code/build/toolkit/solidity-sdk/solidity-sdk-5.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol similarity index 100% rename from .snippets/code/build/toolkit/solidity-sdk/solidity-sdk-5.sol rename to .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-1.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-1.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-1.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-1.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-2.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-2.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-2.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-2.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-3.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-3.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-3.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-3.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-4.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-4.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-4.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-4.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-5.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-5.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-5.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-5.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-6.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-6.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-6.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-6.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-7.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-7.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-7.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-7.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-8.ts b/.snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-8.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/protocols-payloads/pl-8.ts rename to .snippets/code/tools/typescript-sdk/guides/protocols-payloads/pl-8.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-0.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-0.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-0.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-0.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-1.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-1.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-1.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-1.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-10.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-10.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-10.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-10.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-11.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-11.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-11.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-11.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-12.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-12.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-12.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-12.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-13.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-13.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-13.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-13.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-14.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-14.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-14.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-14.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-15.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-15.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-15.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-15.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-16.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-16.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-16.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-16.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-17.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-17.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-17.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-17.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-18.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-18.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-18.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-18.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-19.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-19.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-19.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-19.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-2.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-2.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-2.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-2.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-20.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-20.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-20.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-20.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-21.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-21.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-21.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-21.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-22.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-22.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-22.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-22.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-23.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-23.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-23.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-23.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-25.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-25.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-25.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-25.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-26.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-26.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-26.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-26.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-27.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-27.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-27.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-27.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-3.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-3.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-3.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-3.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-4.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-4.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-4.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-4.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-5.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-5.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-5.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-5.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-6.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-6.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-6.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-6.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-7.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-7.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-7.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-7.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-8.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-8.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-8.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-8.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-9.ts b/.snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-9.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/sdk-layout/layout-9.ts rename to .snippets/code/tools/typescript-sdk/guides/sdk-layout/layout-9.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/vaas-protocols/solidity-sdk.sol b/.snippets/code/tools/typescript-sdk/guides/vaas-protocols/solidity-sdk.sol similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/vaas-protocols/solidity-sdk.sol rename to .snippets/code/tools/typescript-sdk/guides/vaas-protocols/solidity-sdk.sol diff --git a/.snippets/code/build/toolkit/typescript-sdk/vaas-protocols/ts-sdk.ts b/.snippets/code/tools/typescript-sdk/guides/vaas-protocols/ts-sdk.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/vaas-protocols/ts-sdk.ts rename to .snippets/code/tools/typescript-sdk/guides/vaas-protocols/ts-sdk.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/addresses.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/addresses.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/addresses.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/addresses.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/cctp.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/cctp.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/cctp.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/cctp.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/config-override.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/config-override.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/config-override.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/config-override.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/config.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/config.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/config.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/config.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/custom-route.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/custom-route.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/custom-route.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/custom-route.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/ethers.js b/.snippets/code/tools/typescript-sdk/sdk-reference/ethers.js similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/ethers.js rename to .snippets/code/tools/typescript-sdk/sdk-reference/ethers.js diff --git a/.snippets/code/build/toolkit/typescript-sdk/example-core-bridge.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/example-core-bridge.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/example-core-bridge.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/example-core-bridge.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/get-chain.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/get-chain.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/get-chain.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/get-chain.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/get-vaa.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/get-vaa.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/get-vaa.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/get-vaa.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/router.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/router.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/router.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/router.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/signers.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/signers.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/signers.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/signers.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/token-bridge-snippet.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/token-bridge-snippet.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/token-bridge-snippet.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/token-bridge-snippet.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/token-bridge.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/token-bridge.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/token-bridge.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/token-bridge.ts diff --git a/.snippets/code/build/toolkit/typescript-sdk/tokens.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts similarity index 100% rename from .snippets/code/build/toolkit/typescript-sdk/tokens.ts rename to .snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts diff --git a/.snippets/text/build/core-messaging/core-messaging-timeline.json b/.snippets/text/build/core-messaging/core-messaging-timeline.json index e583898c3..6af8702af 100644 --- a/.snippets/text/build/core-messaging/core-messaging-timeline.json +++ b/.snippets/text/build/core-messaging/core-messaging-timeline.json @@ -1,21 +1,21 @@ [ { - "title": "[Send Messages](/docs/build/core-messaging/core-contracts/#sending-messages)", + "title": "[Send Messages](/docs/products/messaging/guides/core-contracts/#sending-messages)", "content": "How-to send messages with Core Contracts.", "icon": ":fontawesome-solid-1:" }, { - "title": "[Interact with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/#receive-a-message)", + "title": "[Interact with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/#receive-a-message)", "content": "How-to use Wormhole Relayer in your messaging workflow.", "icon": ":fontawesome-solid-2:" }, { - "title": "[Receive Messages](/docs/build/core-messaging/core-contracts/#receiving-messages)", + "title": "[Receive Messages](/docs/products/messaging/guides/core-contracts/#receiving-messages)", "content": "How-to verify and parse received messages.", "icon": ":fontawesome-solid-3:" }, { - "title": "[Validate the Emitter](/docs/build/core-messaging/core-contracts/#validating-the-emitter)", + "title": "[Validate the Emitter](/docs/products/messaging/guides/core-contracts/#validating-the-emitter)", "content": "How-to verify messages came from a trusted sender.", "icon": ":fontawesome-solid-4:" } diff --git a/.snippets/text/build/transfers/connect/connect-timeline.json b/.snippets/text/build/transfers/connect/connect-timeline.json index 140b04685..ae528383f 100644 --- a/.snippets/text/build/transfers/connect/connect-timeline.json +++ b/.snippets/text/build/transfers/connect/connect-timeline.json @@ -1,16 +1,16 @@ [ { - "title": "[Integrate Connect](/docs/build/transfers/connect/overview/#integrate-connect)", + "title": "[Integrate Connect](TODO)", "content": "How-to install via npm package or use hosted CDN.", "icon": ":fontawesome-solid-1:" }, { - "title": "[Configure data](/docs/build/transfers/connect/configuration/configure-data/)", + "title": "[Configure data](/docs/products/connect/configuration/data/)", "content": "How-to specify networks, RPCs, supported tokens, and more.", "icon": ":fontawesome-solid-2:" }, { - "title": "[Customize styling](/docs/build/transfers/connect/configuration/configure-theme/)", + "title": "[Customize styling](/docs/products/connect/configuration/theme/)", "content": "How-to style your widget with color schemes, fonts, and layout options.", "icon": ":fontawesome-solid-3:" } diff --git a/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json b/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json index 50a3584d0..b40d42349 100644 --- a/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json +++ b/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json @@ -5,12 +5,12 @@ "icon": ":fontawesome-solid-1:" }, { - "title": "[Configure NTTs](/docs/build/transfers/native-token-transfers/configuration/)", + "title": "[Configure NTTs](/docs/products/native-token-transfers/configuration/access-control/)", "content": "Set NTT configuration options to manage Owner and Pauser access control roles and rate-limiting.", "icon": ":fontawesome-solid-2:" }, { - "title": "[Deploy NTTs](/docs/build/transfers/native-token-transfers/deployment-process/)", + "title": "[Deploy NTTs](/docs/products/native-token-transfers/guides/)", "content": "Deploy your NTT to EVM chains and Solana.", "icon": ":fontawesome-solid-3:" }, diff --git a/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json b/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json deleted file mode 100644 index ed8a8091f..000000000 --- a/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "title": "[Core Contracts](/docs/learn/infrastructure/core-contracts/)", - "content": "Messages are sent from a source contract to the Wormhole Core Contract on the source chain, which publishes them on-chain.", - "icon": ":fontawesome-solid-1:" - }, - { - "title": "[Guardians](/docs/learn/infrastructure/guardians/)", - "content": "Guardians validate these messages before forwarding them to the target chain.", - "icon": ":fontawesome-solid-2:" - }, - { - "title": "[Verifiable Action Approval (VAA)](/docs/learn/infrastructure/vaas/)", - "content": "The validated message is encapsulated in a VAA (Verifiable Action Approval), combining the message with Guardian signatures to create a proof.", - "icon": ":fontawesome-solid-3:" - }, - { - "title": "[Relayers](/docs/learn/infrastructure/relayer/)", - "content": "A relayer relays the VAA to the target chain, which the Wormhole Core Contract then verifies on the target chain.", - "icon": ":fontawesome-solid-4:" - } -] \ No newline at end of file diff --git a/.snippets/text/build/reference/chain-ids/chain-ids.md b/.snippets/text/products/reference/chain-ids/chain-ids.md similarity index 100% rename from .snippets/text/build/reference/chain-ids/chain-ids.md rename to .snippets/text/products/reference/chain-ids/chain-ids.md diff --git a/.snippets/text/build/reference/consistency-levels/consistency-levels.md b/.snippets/text/products/reference/consistency-levels/consistency-levels.md similarity index 100% rename from .snippets/text/build/reference/consistency-levels/consistency-levels.md rename to .snippets/text/products/reference/consistency-levels/consistency-levels.md diff --git a/.snippets/text/build/reference/contract-addresses/cctp.md b/.snippets/text/products/reference/contract-addresses/cctp.md similarity index 100% rename from .snippets/text/build/reference/contract-addresses/cctp.md rename to .snippets/text/products/reference/contract-addresses/cctp.md diff --git a/.snippets/text/build/reference/contract-addresses/core-contracts.md b/.snippets/text/products/reference/contract-addresses/core-contracts.md similarity index 100% rename from .snippets/text/build/reference/contract-addresses/core-contracts.md rename to .snippets/text/products/reference/contract-addresses/core-contracts.md diff --git a/.snippets/text/build/reference/contract-addresses/read-only.md b/.snippets/text/products/reference/contract-addresses/read-only.md similarity index 100% rename from .snippets/text/build/reference/contract-addresses/read-only.md rename to .snippets/text/products/reference/contract-addresses/read-only.md diff --git a/.snippets/text/build/reference/contract-addresses/relayer.md b/.snippets/text/products/reference/contract-addresses/relayer.md similarity index 100% rename from .snippets/text/build/reference/contract-addresses/relayer.md rename to .snippets/text/products/reference/contract-addresses/relayer.md diff --git a/.snippets/text/build/reference/contract-addresses/token-bridge.md b/.snippets/text/products/reference/contract-addresses/token-bridge.md similarity index 100% rename from .snippets/text/build/reference/contract-addresses/token-bridge.md rename to .snippets/text/products/reference/contract-addresses/token-bridge.md diff --git a/.snippets/text/build/start-building/testnet-faucets/testnet-faucets.md b/.snippets/text/products/reference/testnet-faucets/testnet-faucets.md similarity index 100% rename from .snippets/text/build/start-building/testnet-faucets/testnet-faucets.md rename to .snippets/text/products/reference/testnet-faucets/testnet-faucets.md diff --git a/build/.pages b/build/.pages deleted file mode 100644 index c13fa51ef..000000000 --- a/build/.pages +++ /dev/null @@ -1,11 +0,0 @@ -title: Build -nav: - - index.md - - start-building - - transfers - - core-messaging - - multigov - - queries - - infrastructure - - toolkit - - reference \ No newline at end of file diff --git a/build/core-messaging/.pages b/build/core-messaging/.pages deleted file mode 100644 index d6ed0b79a..000000000 --- a/build/core-messaging/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Core Messaging -nav: - - index.md - - 'Wormhole Relayer': 'wormhole-relayers.md' - - 'Core Contracts': 'core-contracts.md' diff --git a/build/index.md b/build/index.md deleted file mode 100644 index 726bb432b..000000000 --- a/build/index.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: Build with Wormhole -description: Learn how to start building multichain solutions on Wormhole, with tips to get started, an overview of the toolkit, and an introduction to the protocols. -template: root-index-page.html ---- - -# Build - -## Quick Start: Step-by-Step Tutorials - -If you learn best by building, start here to build with the Wormhole TypeScript SDK: - -- [**Transfer Tokens via the Token Bridge**](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/){target=\_blank} - use the [Wormhole SDK's](/docs/build/toolkit/typescript-sdk/){target=\_blank} Token Bridge method to move wrapped assets across networks - -- [**Transfer USDC via CCTP and Wormhole SDK**](/docs/tutorials/typescript-sdk/usdc-via-cctp/){target=\_blank} - combine the [Wormhole SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} and Circle's Cross-Chain Transfer Protocol (CCTP) to bridge native USDC across networks - -Alternatively, start here to work with Wormhole contracts directly: - -- [**Create Multichain Messaging Contracts**](/docs/tutorials/solidity-sdk/cross-chain-contracts/) - create mulitchain contracts using Wormhole's Solidity SDK. You will deploy smart contracts and send messages across chains - -- [**Create Multichain Token Transfer Contracts**](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) - create multichain token transfers using Wormhole's Solidity SDK. You will build and deploy smart contracts to send tokens from one blockchain to another - -## Builder Essentials - -Access essential information and tools quickly: - -
- -- :octicons-tools-16:{ .lg .middle } **Supported Networks** - - --- - - Supported blockchains by environment - main or testnet availability and quick links to the website, documentation, and block explorer for each network. - - [:custom-arrow: Supported Networks](/docs/build/start-building/supported-networks/) - -- :octicons-tools-16:{ .lg .middle } **Testnet Faucets** - - --- - - Links to testnet token faucets for supported networks. - - [:custom-arrow: Get Testnet Tokens](/docs/build/start-building/testnet-faucets/) - -- :octicons-tools-16:{ .lg .middle } **Wormhole TypeScript SDK** - - --- - - Your guide to Wormhole SDK installation and usage, concepts overview, and code samples. - - [:custom-arrow: Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/wormhole-sdk/) - -- :octicons-tools-16:{ .lg .middle } **Reference** - - --- - - Wormhole chain ID, contract address, address formatting and conversion, and consistency information. - - [:custom-arrow: Reference](/docs/build/reference/) - -
- -## Integrate Transfer Products - -
- -- :octicons-tools-16:{ .lg .middle } **Multichain Transfers** - - --- - - - **Connect UI widget** - easy-to-use UI for multichain asset transfers via Wormhole in a web application - - **Native Token Transfers (NTT)** - native asset transfer, without the need for wrapped assets - - **Token Bridge** - transfer wrapped assets with optional message payloads - - **Settlement** - intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more - - [:custom-arrow: Build Multichain Transfers](/docs/build/transfers/) - -
- -## Access Real-Time Data - -
- -- :octicons-tools-16:{ .lg .middle } **Real-Time Data** - - --- - - - **Wormhole Queries** - on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy - - **Supported query types** - includes query equivalents for `eth_call` (with options for timestamp and finality), `sol_account`, and `sol_pda` - - **Use familiar endpoints** - make calls against the RPC provider endpoints you already know and use - - [:custom-arrow: Build with Queries](/docs/build/queries/) - -
- -## Multichain Governance - -
- -- :octicons-tools-16:{ .lg .middle } **MultiGov** - - --- - - - **Wormhole's MultiGov** - a multichain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks - - **Hub-and-spoke model** - spoke chain contracts handle local voting and proposals with results sent to the hub for vote aggregation and tallying, proposal management, and coordinating governance across connected chains - - **Wormhole security** - moving vote weight checkpoints, timelocks, and Wormhole verification keep governance activity secure - - [:custom-arrow: Build with MultiGov](/docs/build/multigov/) - -
- diff --git a/build/infrastructure/.pages b/build/infrastructure/.pages deleted file mode 100644 index a81fc0035..000000000 --- a/build/infrastructure/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Infrastructure -nav: - - index.md - - relayers - - spy diff --git a/build/infrastructure/index.md b/build/infrastructure/index.md deleted file mode 100644 index 8dcc26453..000000000 --- a/build/infrastructure/index.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Run Infrastructure Services -description: Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. -# template: root-index-page.html ---- - -# Infrastructure - -## Get Started - -Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. - -
- -- :octicons-terminal-16:{ .lg .middle } **Relayers** - - --- - - Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. - - [:custom-arrow: Run a relayer](/docs/infrastructure/relayers/run-relayer/) - -
- -
- -- :octicons-terminal-16:{ .lg .middle } **Spy** - - --- - - Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. - - [:custom-arrow: Run a Spy](/docs/infrastructure/spy/run-spy/) - -
diff --git a/build/infrastructure/relayers/.pages b/build/infrastructure/relayers/.pages deleted file mode 100644 index f96d27c04..000000000 --- a/build/infrastructure/relayers/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Relayers -nav: - - index.md - - 'Run a Custom Relayer': 'run-relayer.md' diff --git a/build/infrastructure/relayers/index.md b/build/infrastructure/relayers/index.md deleted file mode 100644 index 6239aab02..000000000 --- a/build/infrastructure/relayers/index.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Relayers -description: Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. -categories: Relayers ---- - -# Relayers - -## Get Started - -
- -- :octicons-terminal-16:{ .lg .middle } **Run a Custom Relayer** - - --- - - This section guides you through developing your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. - -
- - Benefits of running your own relayer: - - - You can add logic to customize the delivery of messages - - You can perform off-chain computations resulting in optimized gas costs - -
- - Requirements for running your own relayer: - - - You are responsible for developing and hosting your relayer - - You are responsible for paying target chain fees - - You are responsible for the liveness of your relayer - -
- - [:custom-arrow: Get started now](/docs/infrastructure/relayers/run-relayer/) - -
- -## Additional Resources - -
- -- :octicons-question-16:{ .lg .middle } **What is a Relayer?** - - --- - - Learn about what a relayer is, what role it plays in the delivery of cross-chain messages, and the different types of relayers in the Wormhole ecosystem. - - [:custom-arrow: Learn more about relayers](/docs/learn/infrastructure/relayer/) - -- :octicons-gear-16:{ .lg .middle } **Simplify the Development Process** - - --- - - Use the Wormhole Relayer Engine package as a foundational toolkit to develop your own customized off-chain relaying service, enabling tailored message handling. - - [:custom-arrow: Check out the Relayer Engine source code](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} - -
diff --git a/build/infrastructure/spy/.pages b/build/infrastructure/spy/.pages deleted file mode 100644 index 2862060b4..000000000 --- a/build/infrastructure/spy/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Spy -nav: - - index.md - - 'Run a Spy': 'run-spy.md' diff --git a/build/infrastructure/spy/index.md b/build/infrastructure/spy/index.md deleted file mode 100644 index 1385172f4..000000000 --- a/build/infrastructure/spy/index.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Spy -description: Discover everything you need to about the Wormhole Spy, a daemon that watches the Guardian Network and subscribe to signed messages. ---- - -# Spy - -## Get Started - -
- -- :octicons-terminal-16:{ .lg .middle } **Run a Spy** - - --- - - The content in this section shows you how you can run your own infrastructure and spin up a Spy daemon locally to subscribe to a stream of messages, also known as Verifiable Action Approvals (VAAs). - - [:custom-arrow: Get started now](/docs/infrastructure/spy/run-spy/) - -
- -## Additional Resources - -
- -- :octicons-question-16:{ .lg .middle } **What is a Spy?** - - --- - - Learn about what a Spy is and what role it plays in the delivery of cross-chain messages. - - [:custom-arrow: Learn more about Spies](/docs/learn/infrastructure/spy/) - -- :octicons-code-16:{ .lg .middle } **Interact with a Spy** - - --- - - Use the Wormhole Spy SDK to subscribe to the stream of signed messages. - - [:custom-arrow: Use the Wormhole Spy SDK](https://github.com/wormhole-foundation/wormhole/blob/main/spydk/js/README.md){target=\_blank} - -- :octicons-bookmark-16:{ .lg .middle } **Alternative Implementations** - - --- - - Check out Beacon, an alternative highly available version of the Wormhole Spy. - - [:custom-arrow: Use Pyth Beacon](https://github.com/pyth-network/beacon){target=\_blank} - -
diff --git a/build/multigov/.pages b/build/multigov/.pages deleted file mode 100644 index 7583c1b18..000000000 --- a/build/multigov/.pages +++ /dev/null @@ -1,8 +0,0 @@ -title: Multichain Governance (MultiGov) -nav: - - index.md - - 'Deploy to EVM': 'deploy-to-evm.md' - - 'Deploy to Solana': 'deploy-to-solana.md' - - 'Upgrade Contracts on EVM Chains': 'upgrade-evm.md' - - 'Upgrade Contracts on Solana': 'upgrade-solana.md' - - 'Technical FAQs': 'faq.md' diff --git a/build/queries/.pages b/build/queries/.pages deleted file mode 100644 index e151b6700..000000000 --- a/build/queries/.pages +++ /dev/null @@ -1,6 +0,0 @@ -title: Real-time Data (Queries) -nav: - - index.md - - 'Overview': overview.md - - 'Use Queries': use-queries.md - - 'FAQs': faqs.md diff --git a/build/queries/index.md b/build/queries/index.md deleted file mode 100644 index 845df06b6..000000000 --- a/build/queries/index.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Wormhole Queries -description: Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. -categories: Queries ---- - -# Queries - -## Get Started - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. - -
- -- :octicons-book-16:{ .lg .middle } **Overview** - - --- - - Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST API endpoint, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Learn about Queries](/docs/build/queries/overview/) - -- :octicons-code-16:{ .lg .middle } **Use Queries** - - --- - - Explore a simple demo of interacting with Wormhole Queries using an `eth_call` request to query the supply of wETH on Ethereum using a Wormhole query. - - [:custom-arrow: Get hands-on](/docs/build/queries/use-queries/) - -- :octicons-book-16:{ .lg .middle } **Query FAQs** - - --- - - Explore frequently asked questions about Wormhole Queries. - - [:custom-arrow: Check out the FAQs](/docs/build/queries/faqs/) - -
diff --git a/build/reference/.pages b/build/reference/.pages deleted file mode 100644 index c4775bfd5..000000000 --- a/build/reference/.pages +++ /dev/null @@ -1,7 +0,0 @@ -title: Reference -nav: - - index.md - - 'Chain IDs' : 'chain-ids.md' - - 'Contract Addresses' : 'contract-addresses.md' - - 'Wormhole Finality': 'consistency-levels.md' - - 'Wormhole Formatted Addresses': 'wormhole-formatted-addresses.md' diff --git a/build/reference/index.md b/build/reference/index.md deleted file mode 100644 index 74263d299..000000000 --- a/build/reference/index.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- - -# Reference - -## Get Started - -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. - -
- -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** - - --- - - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) - -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** - - --- - - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) - -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** - - --- - - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. - - This includes the following protocol contracts: - - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP - - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) - -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** - - --- - - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) - -
diff --git a/build/start-building/.pages b/build/start-building/.pages deleted file mode 100644 index 970b3c6a5..000000000 --- a/build/start-building/.pages +++ /dev/null @@ -1,8 +0,0 @@ -title: Start Building -nav: - - index.md - - 'Product Comparison': 'products.md' - - 'Use Cases': 'use-cases.md' - - 'Supported Networks': 'supported-networks.md' - - 'Testnet Faucets': 'testnet-faucets.md' - - 'Explorer': 'https://wormholescan.io/' diff --git a/build/start-building/index.md b/build/start-building/index.md deleted file mode 100644 index 0e0638afb..000000000 --- a/build/start-building/index.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Start Building -description: This section has all you need to start developing with Wormhole, including a guide to supported networks, tool sets, and code examples. ---- - -# Start Building - -Wormhole's role as a Generic Message Passing (GMP) protocol means it facilitates interoperability across multiple areas of project development. The following sections will help you locate the tools most relevant to your development needs whether you are focused on building frontend user interfaces or smart contracts and protocols. This section also links to developer resources like references and code examples which are helpful for all builders looking to integrate with Wormhole. - -## Get Hands-On - -
- -- :octicons-repo-16:{ .lg .middle } **Tutorials** - - --- - - Follow in-depth, step-by-step tutorials to learn how to build cross-chain contracts, integrate Wormhole's SDK, and more. - - [:custom-arrow: Explore tutorials](/docs/tutorials/) - -
- -## Essential Resources for Development - -
- -- :octicons-broadcast-16:{ .lg .middle } **Supported Networks** - - --- - - Explore the blockchains supported by Wormhole for cross-chain communication and asset transfers. Understand which networks are available for both Testnet and Mainnet environments. - - [:custom-arrow: Discover supported networks](/docs/build/start-building/supported-networks/) - -- :octicons-goal-16:{ .lg .middle } **Testnet Faucets** - - --- - - Get Testnet tokens to start experimenting with cross-chain transfers and contract deployment. - - [:custom-arrow: Find Testnet faucets](/docs/build/start-building/testnet-faucets/) - -- :octicons-list-unordered-16:{ .lg .middle } **Reference** - - --- - - Access the essential Wormhole chain IDs and smart contract addresses for messaging protocols, token bridges, and other key components. - - [:custom-arrow: Explore Reference](/docs/build/reference/){target=\_blank} - -
diff --git a/build/toolkit/.pages b/build/toolkit/.pages deleted file mode 100644 index 38f4108e9..000000000 --- a/build/toolkit/.pages +++ /dev/null @@ -1,8 +0,0 @@ -title: Toolkit -nav: - - index.md - - typescript-sdk - - 'Solidity SDK': 'solidity-sdk.md' - - 'Wormholescan API': 'https://wormholescan.io/#/developers/api-doc' -# - 'Development Environment': 'dev-env.md' -# - 'FAQs': 'faqs.md' diff --git a/build/toolkit/index.md b/build/toolkit/index.md deleted file mode 100644 index b5619a221..000000000 --- a/build/toolkit/index.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Wormhole Tooling -description: This page lists key dev tools, including the WormholeScan Explorer, Wormhole CLI, Wormhole SDKs, and APIs for querying network data. -categories: Solidity-SDK ---- - -# Wormhole Tooling - -Regardless of which network development environment you are using, there are a few Wormhole-specific tools you should know about. - -## Get Started - -
- -- :octicons-telescope-16:{ .lg .middle } **Wormholescan** - - --- - - Wormholescan is an explorer for looking at individual transfer statuses on Mainnet and Testnet. - - [:custom-arrow: Review transactions on Wormholescan](https://wormholescan.io){target=\_blank} - -- :octicons-plug-16:{ .lg .middle } **Wormholescan API** - - --- - - Leverage the Wormholescan API to programmatically access Wormhole network data, including transaction details and VAAs. - - [:custom-arrow: Explore the Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} - -- :octicons-code-square-16:{ .lg .middle } **Wormhole CLI Tool** - - --- - - The Wormhole CLI is a Swiss-Army knife utility command line tool. It is excellent for creating one-off VAAs, parsing VAAs, reading Wormhole contract configurations, and more. - - [:custom-arrow: Get started with the CLI](/docs/build/toolkit/cli/) - -- :octicons-code-square-16:{ .lg .middle } **Wormhole SDK** - - --- - - Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC transfers. - - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/typescript-sdk/) - -- :octicons-code-square-16:{ .lg .middle } **Solidity SDK** - - --- - - Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains. - - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/solidity-sdk/) - -- :octicons-beaker-16:{ .lg .middle } **Tilt** - - --- - - Learn about Tilt, a Wormhole developer environment with a local Kubernetes set up for cross-chain testing with Guardian nodes and relayers for seamless development. - - [:custom-arrow: Get started with Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} - - - -
- -## Additional Resources - -
- -- :octicons-code-square-16:{ .lg .middle } **Wormhole Spy SDK** - - --- - - The Wormhole Spy SDK allows you to listen to all the Guardian Network activity. - - [:custom-arrow: Check out the Spy SDK repository](https://github.com/wormhole-foundation/wormhole/tree/main/spydk/js){target=\_blank} - -- :octicons-pencil-16:{ .lg .middle } **VAA Parser** - - --- - - The VAA Parser is a resource for parsing out details of an encoded VAA. - - [:custom-arrow: Try the VAA Parser](https://wormholescan.io/#/developers/vaa-parser){target=\_blank} - -
diff --git a/build/toolkit/typescript-sdk/index.md b/build/toolkit/typescript-sdk/index.md deleted file mode 100644 index 4c97b8137..000000000 --- a/build/toolkit/typescript-sdk/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Wormhole SDK -description: The Wormhole SDK provides tools for cross-chain communication, token bridges, and more, enabling developers to integrate with multiple blockchain environments. -categories: Typescript-SDK ---- - -# Wormhole SDK - -## Get Started - -The Wormhole SDK provides developers with essential tools for cross-chain communication, token bridges, and more. This SDK enables seamless interaction between different blockchain environments with a focus on performance and usability. - -
- -- :octicons-book-16:{ .lg .middle } **Wormhole SDK** - - --- - - Learn about the core functionalities of the Wormhole SDK, including how to use its features for building cross-chain applications. - - [:custom-arrow: Explore the SDK](/docs/build/toolkit/typescript-sdk/wormhole-sdk/) - -- :octicons-code-16:{ .lg .middle } **Layouts** - - --- - - Discover how to define, serialize, and deserialize data structures using the Wormhole SDK's layout system, ensuring efficient cross-chain communication. - - [:custom-arrow: Learn about layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/) - -
diff --git a/build/transfers/.pages b/build/transfers/.pages deleted file mode 100644 index 05ffc8a56..000000000 --- a/build/transfers/.pages +++ /dev/null @@ -1,8 +0,0 @@ -title: Multichain Transfers -nav: - - index.md - - connect - - native-token-transfers - - settlement - - 'Token Bridge': 'token-bridge.md' - - 'CCTP Bridge': 'cctp.md' diff --git a/build/transfers/connect/.pages b/build/transfers/connect/.pages deleted file mode 100644 index 6bf304dd7..000000000 --- a/build/transfers/connect/.pages +++ /dev/null @@ -1,9 +0,0 @@ -title: Connect UI Widget -nav: - - index.md - - 'Overview': overview.md - - 'Routes': routes.md - - 'Features': features.md - - 'Configuration': configuration - - 'v1 Migration': upgrade.md - - 'FAQS': faqs.md \ No newline at end of file diff --git a/build/transfers/connect/configuration/.pages b/build/transfers/connect/configuration/.pages deleted file mode 100644 index 31cfbdf5a..000000000 --- a/build/transfers/connect/configuration/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Connect Configuration -nav: - - index.md - - 'Data': configure-data.md - - 'Theme': configure-theme.md \ No newline at end of file diff --git a/build/transfers/connect/configuration/index.md b/build/transfers/connect/configuration/index.md deleted file mode 100644 index ed8f73b11..000000000 --- a/build/transfers/connect/configuration/index.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -## Configure Connect - -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. - -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. - -!!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for instructions. - - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/build/transfers/connect/configuration-v0/){target=\_blank}. - -
- -- :octicons-database-16:{ .lg .middle } **Data** - - --- - - Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - - - [:custom-arrow: Get started](/docs/build/transfers/connect/configuration/configure-data/) - -- :octicons-apps-16:{ .lg .middle } **Theme** - - --- - - Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. - - [:custom-arrow: Explore routes](/docs/build/transfers/connect/configuration/configure-theme/) - -
diff --git a/build/transfers/index.md b/build/transfers/index.md deleted file mode 100644 index 7ff0ea1ef..000000000 --- a/build/transfers/index.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Multichain Transfers -description: This section guides you through using Wormhole products to securely and efficiently transfer assets and messages across multiple blockchains. ---- - -# Multichain Transfers - -Wormhole transfer products offer multiple asset transfer options to meet developer needs and use cases. These sections include guides to integrate and use Wormhole transfer products to securely and efficiently transfer assets and messages across multiple blockchains. - -Use the following links to jump directly to each Wormhole transfer product page or continue on for a feature-based product comparison. - -- [**Connect**](/docs/build/transfers/connect/) - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup -- [**Native Token Transfers (NTT)**](/docs/build/transfers/native-token-transfers/) - a mechanism to transfer native tokens cross-chain seamlessly without converting to a wrapped asset -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism -- [**Settlement**](/docs/build/transfers/settlement/) - an intent protocol suite for fast multichain transfers, optimizing liquidity flows and interoperability without relying on traditional bridging methods - -## Products By Feature - -While all of these products handle token transfers, there are additional features to consider when selecting the best fit for your project needs. - -
- -- :octicons-file-code-16:{ .lg .middle } **Message Payload** - - --- - - Send message payloads for social platforms, NFTs, and more with Token Bridge's lock and mint wrapped token mechanism. - - [:custom-arrow: Discover Token Bridge](/docs/build/transfers/token-bridge/) - -- :octicons-file-code-16:{ .lg .middle } **Native Assets** - - --- - - Eliminate the need for wrapped tokens and issue native multichain assets with Native Token Transfers (NTT). - - [:custom-arrow: Discover Native Token Transfers](/docs/build/transfers/native-token-transfers/) - - -- :octicons-file-code-16:{ .lg .middle } **Speed at Scale** - - --- - - Unleash institutional-scale digital asset settlement with Wormhole Settlement's intent-based asset transfers and liquidity layer. - - [:custom-arrow: Discover Settlement](/docs/build/transfers/settlement/) - -- :octicons-gear-16:{ .lg .middle } **Plug-and-Play UI** - - --- - - Add Wormhole's bridge UI to your dApp, no smart contract development required, with Connect. - - [:custom-arrow: Discover Connect](/docs/build/transfers/connect/) - -
- -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Product Comparison** - - --- - - Compare Wormhole's cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - - [:custom-arrow: Compare Products](/docs/build/start-building/products/) - -- :octicons-book-16:{ .lg .middle } **Use Cases** - - --- - - Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) - - -
diff --git a/build/transfers/native-token-transfers/.pages b/build/transfers/native-token-transfers/.pages deleted file mode 100644 index a3f09de77..000000000 --- a/build/transfers/native-token-transfers/.pages +++ /dev/null @@ -1,8 +0,0 @@ -title: Native Token Transfers -nav: - - index.md - - deployment-process - - 'NTT CLI Commands': 'cli-commands.md' - - configuration - - 'Managers and Transceivers': 'managers-transceivers.md' - - 'FAQS': faqs.md \ No newline at end of file diff --git a/build/transfers/native-token-transfers/configuration/.pages b/build/transfers/native-token-transfers/configuration/.pages deleted file mode 100644 index 3cf9e420f..000000000 --- a/build/transfers/native-token-transfers/configuration/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: NTT Configuration -nav: - - index.md - - 'Rate Limiting': 'rate-limiting.md' - - 'Access Control': 'access-control.md' diff --git a/build/transfers/native-token-transfers/configuration/index.md b/build/transfers/native-token-transfers/configuration/index.md deleted file mode 100644 index ee32ef34b..000000000 --- a/build/transfers/native-token-transfers/configuration/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Native Token Transfers (NTT) - Configuration -description: This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -categories: NTT, Transfer ---- - -# Configure Native Token Transfers (NTT) - -## Get Started - -This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. - -
- -- :octicons-clock-16:{ .lg .middle } **Rate Limiting** - - --- - - Discover options for configuring rate limits and how queueing effects transaction flow. - - [:custom-arrow: Explore rate limit options](/docs/build/transfers/native-token-transfers/configuration/rate-limiting/) - -- :octicons-unlock-16:{ .lg .middle } **Access Control** - - --- - - Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. - - [:custom-arrow: Explore access control roles](/docs/build/transfers/native-token-transfers/configuration/access-control/) - -
diff --git a/build/transfers/native-token-transfers/deployment-process/.pages b/build/transfers/native-token-transfers/deployment-process/.pages deleted file mode 100644 index f3efbd38f..000000000 --- a/build/transfers/native-token-transfers/deployment-process/.pages +++ /dev/null @@ -1,9 +0,0 @@ -title: Deployment Process -nav: - - index.md - - 'Installation': 'installation.md' - - 'Deploy to EVM': 'deploy-to-evm.md' - - 'Deploy to EVM via Launchpad': 'evm-launchpad.md' - - 'Deploy to Solana': 'deploy-to-solana.md' - - 'Post Deployment': 'post-deployment.md' - - 'Troubleshooting': 'troubleshooting.md' \ No newline at end of file diff --git a/build/transfers/native-token-transfers/deployment-process/index.md b/build/transfers/native-token-transfers/deployment-process/index.md deleted file mode 100644 index 6f9323b8b..000000000 --- a/build/transfers/native-token-transfers/deployment-process/index.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Native Token Transfers (NTT) - Deployment -description: This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. -categories: NTT, Transfer ---- - -# Deploy Native Token Transfers (NTT) - -## Get Started - -This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. - -
- -- :octicons-download-16:{ .lg .middle } **Installation** - - --- - - Prerequisites and commands for installing the NTT CLI and working with the NTT framework. - - [:custom-arrow: Install the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** - - --- - - Find information on preparing for NTT deployment to EVM, including an example NTT token repository. - - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** - - --- - - Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. - - [:custom-arrow: Deploy via Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) - -- :octicons-search-16:{ .lg .middle } **Post Deployment** - - --- - - Learn how to best monitor and maintain your NTT deployment to get the most out of your Wormhole integration while providing security for users. - - [:custom-arrow: Explore next steps](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) - -- :octicons-alert-16:{ .lg .middle } **Troubleshooting** - - --- - - Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. - - [:custom-arrow: Get help](/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/) - -
diff --git a/build/transfers/settlement/.pages b/build/transfers/settlement/.pages deleted file mode 100644 index f4b6a88b6..000000000 --- a/build/transfers/settlement/.pages +++ /dev/null @@ -1,6 +0,0 @@ -title: Wormhole Settlement -nav: - - index.md - - 'Build on the Wormhole Liquidity Layer': 'liquidity-layer.md' - - 'Run a Wormhole Settlement Solver': 'solver.md' - - 'FAQs': 'faqs.md' diff --git a/build/transfers/settlement/index.md b/build/transfers/settlement/index.md deleted file mode 100644 index a2954a26a..000000000 --- a/build/transfers/settlement/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Wormhole Settlement -description: Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. -categories: Settlement, Transfer ---- - -# Wormhole Settlement - -## Get Started - -This section provides resources to build with Wormhole Settlement, including integrating the Liquidity Layer into your application and running a Solver for efficient cross-chain asset transfers. - -
- -- :octicons-code-16:{ .lg .middle } **Build on the Liquidity Layer** - - --- - - Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. - - [:custom-arrow: Build on the Liquidity layer](/docs/build/transfers/settlement/liquidity-layer/) - -- :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** - - --- - - Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - - [:custom-arrow: Run a Solver](/docs/build/transfers/settlement/solver/) - -
\ No newline at end of file diff --git a/images/tutorials/connect/react-dapp/connect-1.webp b/images/products/connect/tutorials/react-dapp/connect-1.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-1.webp rename to images/products/connect/tutorials/react-dapp/connect-1.webp diff --git a/images/tutorials/connect/react-dapp/connect-2.webp b/images/products/connect/tutorials/react-dapp/connect-2.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-2.webp rename to images/products/connect/tutorials/react-dapp/connect-2.webp diff --git a/images/tutorials/connect/react-dapp/connect-3.webp b/images/products/connect/tutorials/react-dapp/connect-3.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-3.webp rename to images/products/connect/tutorials/react-dapp/connect-3.webp diff --git a/images/tutorials/connect/react-dapp/connect-4.webp b/images/products/connect/tutorials/react-dapp/connect-4.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-4.webp rename to images/products/connect/tutorials/react-dapp/connect-4.webp diff --git a/images/tutorials/connect/react-dapp/connect-5.webp b/images/products/connect/tutorials/react-dapp/connect-5.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-5.webp rename to images/products/connect/tutorials/react-dapp/connect-5.webp diff --git a/images/tutorials/connect/react-dapp/connect-6.webp b/images/products/connect/tutorials/react-dapp/connect-6.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-6.webp rename to images/products/connect/tutorials/react-dapp/connect-6.webp diff --git a/images/tutorials/connect/react-dapp/connect-7.webp b/images/products/connect/tutorials/react-dapp/connect-7.webp similarity index 100% rename from images/tutorials/connect/react-dapp/connect-7.webp rename to images/products/connect/tutorials/react-dapp/connect-7.webp diff --git a/images/build/core-messaging/wormhole-relayers/relayer-1.webp b/images/products/messaging/wormhole-relayers/relayer-1.webp similarity index 100% rename from images/build/core-messaging/wormhole-relayers/relayer-1.webp rename to images/products/messaging/wormhole-relayers/relayer-1.webp diff --git a/images/learn/governance/multigov-detailed.webp b/images/products/multigov/concepts/architecture/multigov-detailed.webp similarity index 100% rename from images/learn/governance/multigov-detailed.webp rename to images/products/multigov/concepts/architecture/multigov-detailed.webp diff --git a/images/learn/governance/multigov-high-level.webp b/images/products/multigov/concepts/architecture/multigov-high-level.webp similarity index 100% rename from images/learn/governance/multigov-high-level.webp rename to images/products/multigov/concepts/architecture/multigov-high-level.webp diff --git a/images/learn/transfers/native-token-transfers/architecture/architecture-1.webp b/images/products/native-token-transfers/concepts/architecture/architecture-1.webp similarity index 100% rename from images/learn/transfers/native-token-transfers/architecture/architecture-1.webp rename to images/products/native-token-transfers/concepts/architecture/architecture-1.webp diff --git a/images/learn/transfers/native-token-transfers/architecture/architecture-2.webp b/images/products/native-token-transfers/concepts/architecture/architecture-2.webp similarity index 100% rename from images/learn/transfers/native-token-transfers/architecture/architecture-2.webp rename to images/products/native-token-transfers/concepts/architecture/architecture-2.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp diff --git a/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp b/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp similarity index 100% rename from images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp rename to images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp diff --git a/images/learn/transfers/settlement/architecture/architecture-1.webp b/images/products/settlement/concepts/architecture/architecture-1.webp similarity index 100% rename from images/learn/transfers/settlement/architecture/architecture-1.webp rename to images/products/settlement/concepts/architecture/architecture-1.webp diff --git a/images/learn/transfers/settlement/architecture/architecture-2.webp b/images/products/settlement/concepts/architecture/architecture-2.webp similarity index 100% rename from images/learn/transfers/settlement/architecture/architecture-2.webp rename to images/products/settlement/concepts/architecture/architecture-2.webp diff --git a/images/learn/transfers/settlement/architecture/architecture-3.webp b/images/products/settlement/concepts/architecture/architecture-3.webp similarity index 100% rename from images/learn/transfers/settlement/architecture/architecture-3.webp rename to images/products/settlement/concepts/architecture/architecture-3.webp diff --git a/images/tutorials/multichain-assets/multichain-tokens/multichain-token-1.webp b/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp similarity index 100% rename from images/tutorials/multichain-assets/multichain-tokens/multichain-token-1.webp rename to images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp diff --git a/images/tutorials/multichain-assets/multichain-tokens/multichain-token-2.webp b/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp similarity index 100% rename from images/tutorials/multichain-assets/multichain-tokens/multichain-token-2.webp rename to images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp diff --git a/images/tutorials/multichain-assets/multichain-tokens/multichain-token-3.webp b/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp similarity index 100% rename from images/tutorials/multichain-assets/multichain-tokens/multichain-token-3.webp rename to images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp diff --git a/images/tutorials/multichain-assets/multichain-tokens/multichain-token-4.webp b/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp similarity index 100% rename from images/tutorials/multichain-assets/multichain-tokens/multichain-token-4.webp rename to images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp diff --git a/images/tutorials/multichain-assets/multichain-tokens/multichain-token-5.webp b/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp similarity index 100% rename from images/tutorials/multichain-assets/multichain-tokens/multichain-token-5.webp rename to images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp diff --git a/images/learn/infrastructure/architecture/architecture-1.webp b/images/protocol/architecture/architecture-1.webp similarity index 100% rename from images/learn/infrastructure/architecture/architecture-1.webp rename to images/protocol/architecture/architecture-1.webp diff --git a/images/build/infrastructure/relayers/run-relayer/relayer-1.webp b/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp similarity index 100% rename from images/build/infrastructure/relayers/run-relayer/relayer-1.webp rename to images/protocol/infrastructure-guides/run-relayer/relayer-1.webp diff --git a/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp b/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp similarity index 100% rename from images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp rename to images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp diff --git a/images/learn/introduction/introduction-1.webp b/images/protocol/introduction/introduction-1.webp similarity index 100% rename from images/learn/introduction/introduction-1.webp rename to images/protocol/introduction/introduction-1.webp diff --git a/learn/.pages b/learn/.pages deleted file mode 100644 index 30c9b84b9..000000000 --- a/learn/.pages +++ /dev/null @@ -1,11 +0,0 @@ -title: Learn -nav: - - index.md - - 'Introduction to Wormhole': 'introduction.md' -# TODO: Product Overview - - infrastructure - - transfers -# TODO: Queries - - governance - - 'Security': 'security.md' - - 'Glossary': 'glossary.md' diff --git a/learn/governance/.pages b/learn/governance/.pages deleted file mode 100644 index bbebe4687..000000000 --- a/learn/governance/.pages +++ /dev/null @@ -1,6 +0,0 @@ -title: Multichain Governance (MultiGov) -nav: - - index.md - - 'Overview': 'overview.md' - - 'Architecture': 'architecture.md' - - 'Theoretical FAQs': 'faq.md' \ No newline at end of file diff --git a/learn/governance/faq.md b/learn/governance/faq.md deleted file mode 100644 index 91a723e32..000000000 --- a/learn/governance/faq.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: MultiGov Theoretical FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -categories: MultiGov ---- - -# FAQs - -## General Questions - -### What is MultiGov? - -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. - -### How does MultiGov differ from traditional DAO governance? - -Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. - -### What are the main components of MultiGov? - -The main components of MultiGov include: - -- **Hub chain** - central coordination point for governance activities -- **Spoke chains** - additional chains where token holders can participate in governance -- **Wormhole integration** - enables secure cross-chain message passing -- **Governance token** - allows holders to participate in governance across all integrated chains diff --git a/learn/governance/index.md b/learn/governance/index.md deleted file mode 100644 index 070a23249..000000000 --- a/learn/governance/index.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: Learn about MultiGov -description: Explore the MultiGov documentation for a comprehensive guide covering architecture, deployment, upgrading, integration, and FAQs. -categories: MultiGov ---- - -# MultiGov - -Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. Get an introduction to the core concepts, explore how the system's components work together, and find answers to common questions to help you navigate the platform effectively. - -## Get Started - -
- -- :octicons-book-16:{ .lg .middle } **Overview** - - --- - - Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. - - [:custom-arrow: Take a first glance at MultiGov](/docs/learn/governance/overview/) - -- :octicons-book-16:{ .lg .middle } **Architecture** - - --- - - Discover MultiGov's hub-and-spoke architecture, enabling EVM and Solana cross-chain governance through coordinated decision-making. - - [:custom-arrow: Learn about MultiGov architecture](/docs/learn/governance/architecture/) - -- :octicons-question-16:{ .lg .middle } **Theoretical FAQs** - - --- - - Find answers to common theoretical questions about MultiGov. - - [:custom-arrow: Find the answer to your theoretical questions](/docs/learn/governance/faq/) - -
- -## Next Steps - -
- -- :octicons-checklist-16:{ .lg .middle } **Begin the MultiGov Integration Process** - - --- - - Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. - - [:custom-arrow: Start the integration process now](/docs/build/multigov/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains** - - --- - - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) - -- :octicons-code-square-16:{ .lg .middle } **Tutorials** - - --- - - Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. - - [:custom-arrow: Create MultiGov solutions](/docs/tutorials/multigov/) - -- :octicons-question-16:{ .lg .middle } **Technical FAQs** - - --- - - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) - -
diff --git a/learn/index.md b/learn/index.md deleted file mode 100644 index 1f89c3859..000000000 --- a/learn/index.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Learn about Wormhole -description: Learn the basics of Wormhole, covering its architecture, messaging protocols, and how it enables multichain communication and asset transfers. -template: root-index-page.html ---- - -# Learn - -These informational sections will help you get to know Wormhole. Start with the fundamentals, then discover Wormhole's multichain transfer products and governance system. - -## Fundamentals - -To understand Wormhole from the ground up, visit the following sections. - -
- -- :octicons-book-16:{ .lg .middle } **Introduction to Wormhole** - - --- - - Learn more about the problems Wormhole solves, explore use cases, and view a list of supported blockchains. - - [:custom-arrow: Introduction to Wormhole](/docs/learn/introduction/) - -- :octicons-book-16:{ .lg .middle } **Messaging Infrastructure** - - --- - - Investigate the messaging protocol architecture with an in-depth exploration of the individual components powering Wormhole's infrastructure. - - [:custom-arrow: Understand Wormhole's infrastructure](/docs/learn/infrastructure/) - -
- -## Multichain Transfers - -Wormhole transfer products offer multiple options to meet your project's needs. Which product is best for your use depends upon the asset transfer type you want to add to your dApp. - -### Wrapped Tokens - -This method is likely familiar to you if you've previously built bridging projects. - -
- -- :octicons-book-16:{ .lg .middle } **Token Bridge** - - --- - - - Use Wormhole deployed contracts to simplify development - - Multichain token transfers through lock-and-mint-mechanism - - Option to include message payload for uses like social platforms - - [:custom-arrow: Learn about Token Bridge](/docs/learn/transfers/token-bridge/) - -
- -### Native Tokens - -Eliminate wrapped assets to preserve your token's native properties across chains. - -
- -- :octicons-book-16:{ .lg .middle } **Native Token Transfers** - - --- - - - Deploy custom smart contracts to retain token ownership and upgrade authority with complete customizability - - No wrapped tokens or liquidity pools to avoid slippage and MEV risk - - Custom attestation is available by adding external verifiers - - [:custom-arrow: Learn about Native Token Transfers](/docs/learn/transfers/native-token-transfers/) - -
- -### Intent-Based Transfers - -Institutional-scale digital asset settlement for individual users and insitutions. - -
- -- :octicons-book-16:{ .lg .middle } **Settlement** - - --- - - - Leverages three protocols, providing flexibility and redundancy - - Chain-agnostic to liquidity on chains, enabling broader chain support - - English auction determines the winning solver for settlement - - USDC as the shuttle asset for seamless cross-chain settlement - - [:custom-arrow: Learn about Settlement](/docs/learn/transfers/settlement/) - -
- -## Governance - -Explore MultiGov, Wormhole's multichain governance solution. - -
- -- :octicons-book-16:{ .lg .middle } **Multichain Governance** - - --- - - - Multichain voting and proposal execution - - Aggregates votes from all chains - - Can integrate with any Wormhole-supported blockchain - - [:custom-arrow: Learn about MultiGov](/docs/learn/governance/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Product Comparison** - - --- - - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - - [:custom-arrow: Compare Products](/docs/build/start-building/products/){target=\_blank} - -- :octicons-book-16:{ .lg .middle } **Use Cases** - - --- - - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) - -
\ No newline at end of file diff --git a/learn/infrastructure/.pages b/learn/infrastructure/.pages deleted file mode 100644 index 636098c56..000000000 --- a/learn/infrastructure/.pages +++ /dev/null @@ -1,9 +0,0 @@ -title: Messaging Infrastructure -nav: - - index.md - - 'Architecture Overview': 'architecture.md' - - 'Core Contracts': 'core-contracts.md' - - 'VAAs': 'vaas.md' - - 'Guardians': 'guardians.md' - - 'Spy': 'spy.md' - - 'Relayers': 'relayer.md' diff --git a/learn/infrastructure/index.md b/learn/infrastructure/index.md deleted file mode 100644 index 87bd03148..000000000 --- a/learn/infrastructure/index.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- - -# Infrastructure Components - -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. - -## Get Started - -Start here for an overview of Wormhole architecture components and security mechanisms: - -
- -- :octicons-book-16:{ .lg .middle } **Architecture Overview** - - --- - - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) - -- :octicons-book-16:{ .lg .middle } **Security** - - --- - - Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - - [:custom-arrow: Learn About Security](/docs/learn/security/) - -
- -## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: - -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] - -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Messaging Components** - - --- - - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) - -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** - - --- - - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. - - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) - -
diff --git a/learn/transfers/.pages b/learn/transfers/.pages deleted file mode 100644 index 70d592ca8..000000000 --- a/learn/transfers/.pages +++ /dev/null @@ -1,7 +0,0 @@ -title: Multichain Transfers -nav: - - index.md - - native-token-transfers - - settlement - - 'Token Bridge': 'token-bridge.md' - - 'CCTP Bridge': 'cctp.md' diff --git a/learn/transfers/native-token-transfers/.pages b/learn/transfers/native-token-transfers/.pages deleted file mode 100644 index ab69536d2..000000000 --- a/learn/transfers/native-token-transfers/.pages +++ /dev/null @@ -1,7 +0,0 @@ -title: Native Token Transfers -nav: - - index.md - - 'Overview': 'overview.md' - - 'Architecture': 'architecture.md' - - 'Deployment Models': 'deployment.md' - - 'Security': 'security.md' \ No newline at end of file diff --git a/learn/transfers/native-token-transfers/index.md b/learn/transfers/native-token-transfers/index.md deleted file mode 100644 index 0ad1e756d..000000000 --- a/learn/transfers/native-token-transfers/index.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: A Quick Look at Native Token Transfers -description: This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- - -# Native Token Transfers - -## Get Started - -This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. - -
- -- :octicons-question-16:{ .lg .middle } **Overview** - - --- - - Dive into an introduction to NTT and discover what NTT is, what its key features are, and the available integration paths. - - [:custom-arrow: Learn more about NTT](/docs/learn/transfers/native-token-transfers/overview/) - -- :octicons-question-16:{ .lg .middle } **Architecture** - - --- - - Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. - - [:custom-arrow: Discover how NTT works](/docs/learn/transfers/native-token-transfers/architecture/) - -- :octicons-book-16:{ .lg .middle } **Deployment Models** - - --- - - The NTT framework offers two deployment models for different token management needs: the hub-and-spoke and burn-and-mint models. - - [:custom-arrow: Check out the deployment models](/docs/learn/transfers/native-token-transfers/deployment/) - -- :octicons-shield-lock-16:{ .lg .middle } **Security** - - --- - - Explore NTT's security measures, including the Global Accountant and governance strategies for seamless token safety. - - [:custom-arrow: Review the security measures](/docs/learn/transfers/native-token-transfers/security/) - -
- -## Next Steps - -Ready to dive in and start building? Check out the following resources to begin the deployment process and make the most of your deployment. - -
- -- :octicons-rocket-16:{ .lg .middle } **Deploy NTT** - - --- - - Explore detailed guides that walk you through the entire deployment process, from installing the NTT CLI to deploying NTT across supported chains. - - [:custom-arrow: Deploy now using the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/) - -- :octicons-checklist-16:{ .lg .middle } **Post Deployment Recommendations** - - --- - - Already deployed your NTT project? Check out these post deployment recommendations and integration demos to get the most out of your deployment. - - [:custom-arrow: Get the most of out your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) - -
diff --git a/learn/transfers/settlement/.pages b/learn/transfers/settlement/.pages deleted file mode 100644 index e9329c638..000000000 --- a/learn/transfers/settlement/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Settlement -nav: - - index.md - - 'Overview': 'overview.md' - - 'Protocol Architectures': 'architecture.md' \ No newline at end of file diff --git a/learn/transfers/settlement/index.md b/learn/transfers/settlement/index.md deleted file mode 100644 index d1e7a166c..000000000 --- a/learn/transfers/settlement/index.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Wormhole Settlement -description: Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. -categories: Settlement, Transfer ---- - -# Wormhole Settlement - -## Get Started - -This section covers Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. - -
- -- :octicons-question-16:{ .lg .middle } **Overview** - - --- - - Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. - - [:custom-arrow: Learn more about Wormhole Settlement](/docs/learn/transfers/settlement/overview/) - -- :octicons-question-16:{ .lg .middle } **Protocol Architectures** - - --- - - Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. - - [:custom-arrow: Discover protocol architectures](/docs/learn/transfers/settlement/architecture/) - -
\ No newline at end of file diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index d9bd41531..f0168ab1d 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -7,17 +7,17 @@ This file includes documentation related to the category: Basics ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/core-contracts.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/guardians.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/relayer.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/spy.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/vaas.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/introduction.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/security.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/core-contracts.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/wormhole-relayers.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md [type: build] @@ -39,11 +39,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -59,7 +59,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -93,14 +93,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -124,7 +124,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -132,7 +132,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -140,9 +140,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -154,7 +154,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -167,7 +167,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -181,12 +181,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -198,17 +198,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -222,7 +222,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -235,7 +235,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -270,7 +270,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -278,13 +278,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -292,7 +292,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -306,7 +306,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -314,12 +314,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -337,7 +337,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -377,11 +377,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -410,7 +410,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -423,7 +423,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -435,7 +435,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -503,7 +503,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -569,7 +569,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -577,7 +577,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -585,12 +585,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -624,7 +624,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -676,7 +676,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -689,7 +689,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -701,7 +701,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -878,7 +878,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -890,7 +890,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -898,12 +898,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -919,10 +919,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -944,7 +944,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -963,7 +963,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -1059,7 +1059,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -1071,7 +1071,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -1136,7 +1136,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -1170,7 +1170,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -1186,15 +1186,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -1338,7 +1338,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -1389,9 +1389,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -1417,7 +1417,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -1528,10 +1528,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -1548,7 +1548,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -1560,18 +1560,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -1589,7 +1589,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -1750,7 +1750,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -1859,7 +1859,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -1882,7 +1882,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -1921,7 +1921,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -1943,7 +1943,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -1984,7 +1984,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -2005,7 +2005,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -2069,7 +2069,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -2089,7 +2089,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index f390bcd1c..35257f6f4 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -15,15 +15,15 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-data.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-theme.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/features.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/routes.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/upgrade.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/react-dapp.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] ## Full content for each doc page @@ -69,10 +69,10 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag --- - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/build/start-building/supported-networks/){target=\_blank}. + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - [:custom-arrow: Get started](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - :octicons-tools-16:{ .lg .middle } **Connect FAQs** @@ -81,7 +81,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [:custom-arrow: Visit FAQs](/docs/build/transfers/connect/faqs/) + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** @@ -89,7 +89,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - [:custom-arrow: Supported Features](/docs/build/transfers/connect/features/) + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) --- END CONTENT --- @@ -111,9 +111,9 @@ Wormhole Connect is a flexible React widget that streamlines cross-chain asset t This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. !!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for instructions. + To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/build/transfers/connect/configuration-v0/){target=\_blank}. + If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}.
@@ -124,7 +124,7 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - [:custom-arrow: Get started](/docs/build/transfers/connect/configuration/configure-data/) + [:custom-arrow: Get started](/docs/products/connect/configuration/data/) - :octicons-apps-16:{ .lg .middle } **Theme** @@ -132,12 +132,12 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. - [:custom-arrow: Explore routes](/docs/build/transfers/connect/configuration/configure-theme/) + [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-data/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- title: Connect Data Configuration @@ -520,7 +520,7 @@ function App() { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-theme/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ --- BEGIN CONTENT --- --- title: Connect Theme & UI Customization @@ -640,7 +640,7 @@ function App() { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/faqs/ +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ --- BEGIN CONTENT --- --- title: Connect FAQs @@ -668,7 +668,7 @@ Connect supports around 30 chains, spanning various blockchain runtimes: - Solana - Move-based chains (Sui, Aptos) -For a complete list of supported chains, see the [Connect-supported chains list](/docs/build/transfers/connect/features/){target=\_blank}. +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## What is gas dropoff? @@ -714,7 +714,7 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/features/ +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- title: Features @@ -761,7 +761,7 @@ This route appears if both of the following conditions are satisfied: ### Token Bridge Relayer {: #token-bridge-relayer} -On the [routes](/docs/build/transfers/connect/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. @@ -821,13 +821,13 @@ The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-d Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -- Multiple ways to bridge assets ([routes](/docs/build/transfers/connect/routes/){target=\_blank}) +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) - Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) - Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer - Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/build/transfers/connect/features/){target=\_blank} at the destination +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/build/transfers/connect/features/){target=\_blank}. +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## Integrate Connect {: #integrate-connect } @@ -862,7 +862,7 @@ const container = document.getElementById('bridge-container'); wormholeConnectHosted(container); ``` -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/build/transfers/connect/upgrade/){target=\_blank} guide. +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. ???- code "v0.x" Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. @@ -897,12 +897,12 @@ The default configuration of Wormhole Connect may not be exactly what you're loo - Restrict the chains that you allow in your app - Add support for your project's token, and eliminate tokens you don't want to reduce noise - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/build/transfers/connect/routes/){target=\_blank} that are available + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/routes/ +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- title: Routes @@ -916,7 +916,7 @@ This page explains the concept of routes in Wormhole Connect. To configure route Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/build/transfers/connect/features/){target=\_blank} to see under which exact conditions the routes appear. +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. ## Token Bridge Routes {: #token-bridge-routes} @@ -983,7 +983,7 @@ Note that if native tBTC is transferred out of these chains to any other outside This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/upgrade/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- title: Wormhole Connect v1.0 Migration Guide @@ -1577,7 +1577,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - [:custom-arrow: Start building](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) @@ -1596,7 +1596,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/connect/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ --- BEGIN CONTENT --- --- title: Integrate Connect into a React DApp Tutorial @@ -1652,7 +1652,7 @@ npm install @wormhole-foundation/wormhole-connect ### Integrate Connect into the Application -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/build/transfers/connect/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: === "JavaScript" @@ -1730,26 +1730,26 @@ To transfer tokens from Sui to Fuji in the Wormhole Connect interface: 2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network 3. Enter the amount of SUI tokens you wish to transfer - ![](/docs/images/tutorials/connect/react-dapp/connect-1.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) 4. Choose to view other routes - ![](/docs/images/tutorials/connect/react-dapp/connect-2.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) 5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) !!! note It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - ![](/docs/images/tutorials/connect/react-dapp/connect-3.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) 6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - ![](/docs/images/tutorials/connect/react-dapp/connect-4.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) 7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - ![](/docs/images/tutorials/connect/react-dapp/connect-5.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. @@ -1757,11 +1757,11 @@ Once the transaction has been submitted, Wormhole Connect will display the progr After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -![](/docs/images/tutorials/connect/react-dapp/connect-6.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. -![](/docs/images/tutorials/connect/react-dapp/connect-7.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) ## Resources @@ -1811,11 +1811,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -1831,7 +1831,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -1865,14 +1865,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -1896,7 +1896,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -1904,7 +1904,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -1912,9 +1912,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -1926,7 +1926,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -1939,7 +1939,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -1953,12 +1953,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -1970,17 +1970,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -1994,7 +1994,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -2007,7 +2007,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -2042,7 +2042,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -2050,13 +2050,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -2064,7 +2064,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2078,7 +2078,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -2086,12 +2086,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -2109,7 +2109,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -2149,11 +2149,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -2182,7 +2182,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -2195,7 +2195,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -2207,7 +2207,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -2275,7 +2275,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -2341,7 +2341,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -2349,7 +2349,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -2357,12 +2357,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -2396,7 +2396,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -2448,7 +2448,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -2461,7 +2461,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -2473,7 +2473,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -2650,7 +2650,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -2662,7 +2662,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -2670,12 +2670,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -2691,10 +2691,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -2716,7 +2716,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2735,7 +2735,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -2831,7 +2831,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -2843,7 +2843,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -2908,7 +2908,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -2942,7 +2942,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -2958,15 +2958,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -3110,7 +3110,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -3161,9 +3161,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -3189,7 +3189,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -3300,10 +3300,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -3320,7 +3320,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -3332,18 +3332,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -3361,7 +3361,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -3522,7 +3522,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -3631,7 +3631,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -3654,7 +3654,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -3693,7 +3693,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -3715,7 +3715,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -3756,7 +3756,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -3777,7 +3777,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -3841,7 +3841,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -3861,7 +3861,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -3883,7 +3883,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -3905,7 +3905,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -3913,7 +3913,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -3929,7 +3929,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -3939,12 +3939,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -4075,7 +4075,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -4134,7 +4134,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -4440,7 +4440,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -4594,7 +4594,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -4689,7 +4689,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 87aada924..234428acc 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -14,17 +14,17 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/faq.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/faq.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-solana.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/treasury-proposal.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md [type: tutorials] ## Full content for each doc page @@ -58,7 +58,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Discover MultiGov's hub-and-spoke architecture, enabling EVM and Solana cross-chain governance through coordinated decision-making. - [:custom-arrow: Learn about MultiGov architecture](/docs/learn/governance/architecture/) + [:custom-arrow: Learn about MultiGov architecture](/docs/products/multigov/concepts/architecture/) - :octicons-question-16:{ .lg .middle } **Theoretical FAQs** @@ -66,7 +66,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Find answers to common theoretical questions about MultiGov. - [:custom-arrow: Find the answer to your theoretical questions](/docs/learn/governance/faq/) + [:custom-arrow: Find the answer to your theoretical questions](/docs/products/multigov/faqs/) @@ -88,7 +88,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -96,7 +96,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - :octicons-code-square-16:{ .lg .middle } **Tutorials** @@ -112,12 +112,12 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/governance/architecture/ +Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ --- BEGIN CONTENT --- --- title: MultiGov Architecture @@ -250,7 +250,7 @@ This architecture ensures that MultiGov can operate securely and efficiently acr ![detailed multigov architecture diagram](/docs/images/learn/governance/multigov-detailed.webp) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/governance/faq/ +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ --- BEGIN CONTENT --- --- title: MultiGov Theoretical FAQs @@ -316,7 +316,7 @@ MultiGov is important because it: The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/learn/governance/architecture/){target=\_blank} page. +For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. ![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/learn/governance/multigov-high-level.webp) @@ -351,7 +351,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -359,7 +359,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** @@ -367,7 +367,7 @@ Take the following steps to get started with a MultiGov integration: Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/build/multigov/upgrade-evm/) + [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** @@ -375,7 +375,7 @@ Take the following steps to get started with a MultiGov integration: Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/build/multigov/upgrade-solana/) + [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - :octicons-question-16:{ .lg .middle } **Technical FAQs** @@ -383,7 +383,7 @@ Take the following steps to get started with a MultiGov integration: Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) @@ -410,7 +410,7 @@ Take the following steps to get started with a MultiGov integration: --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- title: Deploy MultiGov on EVM Chains @@ -516,7 +516,7 @@ These parameters can be queried using their respective getter functions on the a To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- title: MultiGov Deployment to Solana @@ -526,7 +526,7 @@ categories: MultiGov # Deploy MultiGov on Solana -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/learn/governance/architecture/){target=\_blank}. +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. @@ -706,7 +706,7 @@ When deploying MultiGov on Solana, several key parameters need to be set. Here a - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/faq/ +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ --- BEGIN CONTENT --- --- title: MultiGov Technical FAQs @@ -729,7 +729,7 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl ### Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/build/start-building/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. ### How are votes aggregated across different chains? @@ -799,7 +799,7 @@ MultiGov includes several mechanisms to handle network issues or temporary chain However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/upgrade-evm/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ --- BEGIN CONTENT --- --- title: Upgrading MultiGov on EVM @@ -869,7 +869,7 @@ MultiGov is designed to be flexible but stable. Due to the system's complexity a - Always test upgrades extensively on testnets before implementing in production --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/upgrade-solana/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ --- BEGIN CONTENT --- --- title: Upgrading MultiGov on Solana @@ -962,7 +962,7 @@ Welcome to the MultiGov tutorials section. In this section, you will find tutori Learn how to propose governance actions on a hub chain, gather votes from spoke chains, aggregate the results, and carry out the final decision. Following these steps, you’ll master end-to-end governance workflows spanning multiple networks. - [:custom-arrow: Start building](/docs/tutorials/multigov/treasury-proposal/) + [:custom-arrow: Start building](/docs/products/multigov/tutorials/treasury-proposal/) @@ -990,7 +990,7 @@ Welcome to the MultiGov tutorials section. In this section, you will find tutori --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/multigov/treasury-proposal/ +Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ --- BEGIN CONTENT --- --- title: MultiGov Guides @@ -1237,11 +1237,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -1257,7 +1257,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -1291,14 +1291,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -1322,7 +1322,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -1330,7 +1330,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -1338,9 +1338,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -1352,7 +1352,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -1365,7 +1365,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -1379,12 +1379,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -1396,17 +1396,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -1420,7 +1420,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -1433,7 +1433,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -1468,7 +1468,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -1476,13 +1476,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -1490,7 +1490,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -1504,7 +1504,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -1512,12 +1512,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -1535,7 +1535,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -1575,11 +1575,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -1608,7 +1608,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -1621,7 +1621,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -1633,7 +1633,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -1701,7 +1701,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -1767,7 +1767,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -1775,7 +1775,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -1783,12 +1783,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -1822,7 +1822,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1874,7 +1874,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -1887,7 +1887,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -1899,7 +1899,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -2076,7 +2076,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -2088,7 +2088,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -2096,12 +2096,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -2117,10 +2117,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -2142,7 +2142,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2161,7 +2161,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -2257,7 +2257,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -2269,7 +2269,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -2334,7 +2334,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -2368,7 +2368,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -2384,15 +2384,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -2536,7 +2536,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -2587,9 +2587,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -2615,7 +2615,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -2726,10 +2726,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -2746,7 +2746,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -2758,18 +2758,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -2787,7 +2787,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -2948,7 +2948,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -3057,7 +3057,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -3080,7 +3080,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -3119,7 +3119,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -3141,7 +3141,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -3182,7 +3182,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -3203,7 +3203,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -3267,7 +3267,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -3287,7 +3287,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -3309,7 +3309,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -3331,7 +3331,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -3339,7 +3339,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -3355,7 +3355,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -3365,12 +3365,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -3501,7 +3501,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -3560,7 +3560,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3866,7 +3866,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -4020,7 +4020,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -4115,7 +4115,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index b32e16b0f..f7590bc7f 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -14,23 +14,23 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/cli-commands.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/access-control.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/rate-limiting.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/troubleshooting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md [type: build] ## Full content for each doc page @@ -65,7 +65,7 @@ This section covers Wormhole's Native Token Transfers (NTT), an open source, fle Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. - [:custom-arrow: Discover how NTT works](/docs/learn/transfers/native-token-transfers/architecture/) + [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) - :octicons-book-16:{ .lg .middle } **Deployment Models** @@ -110,7 +110,7 @@ Ready to dive in and start building? Check out the following resources to begin --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/architecture/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- title: Native Token Transfers Architecture @@ -164,10 +164,10 @@ How it works: 2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred 3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain -![NTT architecture diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-1.webp) +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) !!! note - [Learn more](/docs/learn/transfers/native-token-transfers/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. #### Custom Transceivers @@ -175,7 +175,7 @@ The NTT framework supports advanced features such as custom transceivers for spe NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -![Custom Attestation with NTT diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-2.webp) +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. @@ -279,8 +279,8 @@ categories: NTT, Transfer !!!tip "Looking to deploy NTT?" If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/){target=\_blank} + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} ## Introduction @@ -327,12 +327,12 @@ The Token Bridge offers a secure, low-effort integration suitable for applicatio - **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract - **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/learn/security/){target=\_blank} +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} - **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process - **Integration** - straightforward and permissionless method to deploy on multiple chains !!! note - [Learn more](/docs/learn/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. ## Supported Token Standards @@ -397,7 +397,7 @@ The process for creating, deploying, and monitoring NTTs is as follows. Select t If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. ## Additional Resources @@ -409,7 +409,7 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - [:custom-arrow: NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/) + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - :octicons-question-16:{ .lg .middle } **NTT FAQs** @@ -417,12 +417,12 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/cli-commands/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- title: NTT CLI Commands @@ -493,7 +493,7 @@ To explore detailed information about any NTT CLI command, including its options Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- @@ -520,7 +520,7 @@ This section contains information on configuring Native Token Transfers (NTT), i Discover options for configuring rate limits and how queueing effects transaction flow. - [:custom-arrow: Explore rate limit options](/docs/build/transfers/native-token-transfers/configuration/rate-limiting/) + [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) - :octicons-unlock-16:{ .lg .middle } **Access Control** @@ -528,12 +528,12 @@ This section contains information on configuring Native Token Transfers (NTT), i Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. - [:custom-arrow: Explore access control roles](/docs/build/transfers/native-token-transfers/configuration/access-control/) + [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/access-control/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ --- BEGIN CONTENT --- --- title: Native Token Transfers Access Control @@ -577,7 +577,7 @@ The `Owner` and the `Pauser` addresses can each pause the contract. Since the co Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/rate-limiting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ --- BEGIN CONTENT --- --- title: Native Token Transfers Rate Limiting @@ -706,7 +706,7 @@ This section provides information on installing Wormhole's Native Token Transfer Find information on preparing for NTT deployment to EVM, including an example NTT token repository. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** @@ -714,7 +714,7 @@ This section provides information on installing Wormhole's Native Token Transfer Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. - [:custom-arrow: Deploy via Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/) + [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -722,7 +722,7 @@ This section provides information on installing Wormhole's Native Token Transfer Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) - :octicons-search-16:{ .lg .middle } **Post Deployment** @@ -738,12 +738,12 @@ This section provides information on installing Wormhole's Native Token Transfer Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. - [:custom-arrow: Get help](/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/) + [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- title: Native Token Transfers EVM Deployment @@ -933,7 +933,7 @@ By default, NTT transfers to EVM blockchains support automatic relaying via the To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- title: Native Token Transfers Solana Deployment @@ -1043,7 +1043,7 @@ Deploying NTT with the CLI on Solana follows a structured process: Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -By default, NTT transfers to Solana require manual [relaying](/docs/learn/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. ## Set Up NTT @@ -1168,7 +1168,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -1189,7 +1189,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ --- BEGIN CONTENT --- --- title: Deploy Native Token Transfers with Launchpad @@ -1245,11 +1245,11 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Launch a Cross-Chain Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) 3. Set the token details: 1. Select the **home network** from the dropdown menu @@ -1258,22 +1258,22 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 4. Provide the **initial supply** 5. To the token details, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) 4. Select the deployment chains: 1. The home network where your token will be deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -1285,33 +1285,33 @@ Expand an existing token to support NTT across multiple chains. This process int 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Expand Your Existing Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) 3. Enter the token details: 1. Choose the home network where your token is already deployed (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) 4. Select the chains to deploy your token to: 1. The home network where your token is already deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 1. Click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -1321,7 +1321,7 @@ Expand an existing token to support NTT across multiple chains. This process int To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) The dashboard provides a high-level view of your token across all deployed chains, including: @@ -1329,7 +1329,7 @@ The dashboard provides a high-level view of your token across all deployed chain - Supply distribution visualization - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) ## Settings @@ -1344,16 +1344,16 @@ From this section, you can also: - **Pause the token** – temporarily turn off transfers on the selected chain - **Deploy to a new chain** – expand your token by deploying it to an additional chain -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) ### Role Management -This section displays key [roles](/docs/build/transfers/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - **Manager’s Owner** – the owner through the `NTTOwner` proxy - **Pauser** – the address authorized to pause transfers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) ### Security Threshold @@ -1364,7 +1364,7 @@ A higher transceiver threshold increases security by requiring more approvals be - **Registered Transceivers** – displays the number of registered transceivers and their addresses - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) ### Peer Chains Limits @@ -1375,7 +1375,7 @@ Define the transfer restrictions for each connected network. You can adjust: Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/installation/ @@ -1414,7 +1414,7 @@ Follow these steps to install the NTT CLI: ntt --version ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/){target=\_blank} to start using the CLI +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI ## Update NTT CLI @@ -1452,7 +1452,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to EVM chains](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-tools-16:{ .lg .middle } **Deploy to Solana** @@ -1460,7 +1460,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to Solana](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) --- END CONTENT --- @@ -1480,7 +1480,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} allows for a direct integration into your infrastructure +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -1515,7 +1515,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ --- BEGIN CONTENT --- --- title: Troubleshooting NTT Deployment @@ -1527,15 +1527,15 @@ categories: NTT, Transfer If you encounter issues during the NTT deployment process, check the following common points: -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#install-dependencies){target=\_blank} +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain - **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#configure-ntt){target=\_blank} + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} - **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file ???- interface "Dockerfile" @@ -1624,7 +1624,7 @@ If you encounter issues during the NTT deployment process, check the following c ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/faqs/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ --- BEGIN CONTENT --- --- title: Native Token Transfers FAQs @@ -2092,11 +2092,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -2112,7 +2112,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -2146,14 +2146,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -2177,7 +2177,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -2185,7 +2185,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -2193,9 +2193,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -2207,7 +2207,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -2220,7 +2220,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -2234,12 +2234,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -2251,17 +2251,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -2275,7 +2275,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -2288,7 +2288,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -2323,7 +2323,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -2331,13 +2331,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -2345,7 +2345,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2359,7 +2359,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -2367,12 +2367,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -2390,7 +2390,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -2430,11 +2430,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -2463,7 +2463,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -2476,7 +2476,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -2488,7 +2488,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -2556,7 +2556,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -2622,7 +2622,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -2630,7 +2630,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -2638,12 +2638,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -2677,7 +2677,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -2729,7 +2729,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -2742,7 +2742,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -2754,7 +2754,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -2931,7 +2931,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -2943,7 +2943,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -2951,12 +2951,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -2972,10 +2972,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -2997,7 +2997,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -3016,7 +3016,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -3112,7 +3112,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -3124,7 +3124,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -3189,7 +3189,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -3223,7 +3223,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -3239,15 +3239,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -3391,7 +3391,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -3442,9 +3442,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -3470,7 +3470,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -3581,10 +3581,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -3601,7 +3601,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -3613,18 +3613,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -3642,7 +3642,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -3803,7 +3803,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -3912,7 +3912,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -3935,7 +3935,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -3974,7 +3974,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -3996,7 +3996,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -4037,7 +4037,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -4058,7 +4058,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -4122,7 +4122,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -4142,7 +4142,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -4164,7 +4164,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -4186,7 +4186,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -4194,7 +4194,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -4210,7 +4210,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -4220,12 +4220,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -4356,7 +4356,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -4415,7 +4415,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -4721,7 +4721,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -4875,7 +4875,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -4970,7 +4970,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index e5c2e10ad..59c615dbd 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -14,7 +14,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md [type: build] @@ -58,12 +58,12 @@ Wormhole Queries offers on-demand access to Guardian-attested on-chain data via Explore frequently asked questions about Wormhole Queries. - [:custom-arrow: Check out the FAQs](/docs/build/queries/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/queries/faqs/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/queries/faqs/ +Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- title: Queries FAQs @@ -211,7 +211,7 @@ For example, many chains have implementations forked from [Geth](https://github. Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. -Be sure to check out the [FAQs](/docs/build/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. +Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. You can also check out the following examples of applications that make use of Wormhole Queries: @@ -435,7 +435,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe @@ -672,11 +672,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -692,7 +692,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -726,14 +726,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -757,7 +757,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -765,7 +765,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -773,9 +773,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -787,7 +787,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -800,7 +800,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -814,12 +814,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -831,17 +831,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -855,7 +855,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -868,7 +868,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -903,7 +903,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -911,13 +911,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -925,7 +925,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -939,7 +939,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -947,12 +947,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -970,7 +970,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -1010,11 +1010,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -1043,7 +1043,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -1056,7 +1056,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -1068,7 +1068,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -1136,7 +1136,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -1202,7 +1202,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -1210,7 +1210,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -1218,12 +1218,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -1257,7 +1257,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1309,7 +1309,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -1322,7 +1322,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -1334,7 +1334,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -1511,7 +1511,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -1523,7 +1523,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -1531,12 +1531,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -1552,10 +1552,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -1577,7 +1577,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -1596,7 +1596,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -1692,7 +1692,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -1704,7 +1704,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -1769,7 +1769,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -1803,7 +1803,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -1819,15 +1819,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -1971,7 +1971,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -2022,9 +2022,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -2050,7 +2050,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -2161,10 +2161,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -2181,7 +2181,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -2193,18 +2193,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -2222,7 +2222,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -2383,7 +2383,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -2492,7 +2492,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -2515,7 +2515,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -2554,7 +2554,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -2576,7 +2576,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -2617,7 +2617,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -2638,7 +2638,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -2702,7 +2702,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -2722,7 +2722,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -2744,7 +2744,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -2766,7 +2766,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -2774,7 +2774,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -2790,7 +2790,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -2800,12 +2800,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -2936,7 +2936,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -2995,7 +2995,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3301,7 +3301,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -3455,7 +3455,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -3550,7 +3550,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 06f0be30a..4b8d69040 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -7,16 +7,16 @@ This file includes documentation related to the category: Reference ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/chain-ids.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/consistency-levels.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/contract-addresses.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/wormhole-formatted-addresses.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/supported-networks.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/testnet-faucets.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md [type: build] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -38,7 +38,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -46,7 +46,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -62,7 +62,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -72,12 +72,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -208,7 +208,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -267,7 +267,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -573,7 +573,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -727,7 +727,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -822,7 +822,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 8801b3d3b..7045e1276 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -13,13 +13,13 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/wormhole-relayers.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md [type: build] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -31,18 +31,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -60,7 +60,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -221,7 +221,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/infrastructure/relayers/ @@ -261,7 +261,7 @@ categories: Relayers
- [:custom-arrow: Get started now](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-relayer/) @@ -275,7 +275,7 @@ categories: Relayers Learn about what a relayer is, what role it plays in the delivery of cross-chain messages, and the different types of relayers in the Wormhole ecosystem. - [:custom-arrow: Learn more about relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn more about relayers](/docs/protocol/infrastructure/relayer/) - :octicons-gear-16:{ .lg .middle } **Simplify the Development Process** @@ -288,7 +288,7 @@ categories: Relayers --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/infrastructure/relayers/run-relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ --- BEGIN CONTENT --- --- title: Run a Relayer @@ -313,7 +313,7 @@ This guide teaches you how to set up and configure a custom relayer for efficien To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs.
- ![Custom relayer](/docs/images/build/infrastructure/relayers/run-relayer/relayer-1.webp) + ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp)
The off-chain components outlined in blue must be implemented.
@@ -454,7 +454,7 @@ The source code for this example is available in the [`relayer-engine` repositor Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. -More details about the Spy are available in the [Spy Documentation](/docs/learn/infrastructure/spy){target=\_blank}. +More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. ### Wormhole Network Spy @@ -646,11 +646,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -666,7 +666,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -700,14 +700,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -731,7 +731,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -739,7 +739,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -747,9 +747,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -761,7 +761,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -774,7 +774,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -788,12 +788,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -805,17 +805,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -829,7 +829,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -842,7 +842,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -877,7 +877,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -885,13 +885,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -899,7 +899,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -913,7 +913,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -921,12 +921,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -944,7 +944,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -984,11 +984,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -1017,7 +1017,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -1030,7 +1030,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -1042,7 +1042,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -1110,7 +1110,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -1176,7 +1176,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -1184,7 +1184,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -1192,12 +1192,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -1231,7 +1231,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1283,7 +1283,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -1296,7 +1296,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -1308,7 +1308,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -1485,7 +1485,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -1497,7 +1497,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -1505,12 +1505,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -1526,10 +1526,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -1551,7 +1551,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -1570,7 +1570,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -1666,7 +1666,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -1678,7 +1678,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -1743,7 +1743,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -1777,7 +1777,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -1793,15 +1793,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -1945,7 +1945,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -1996,9 +1996,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -2024,7 +2024,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -2135,10 +2135,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -2155,7 +2155,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -2167,18 +2167,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -2196,7 +2196,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -2357,7 +2357,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -2466,7 +2466,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -2489,7 +2489,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -2528,7 +2528,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -2550,7 +2550,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -2591,7 +2591,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -2612,7 +2612,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -2676,7 +2676,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -2696,7 +2696,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -2718,7 +2718,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -2740,7 +2740,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -2748,7 +2748,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -2764,7 +2764,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -2774,12 +2774,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -2910,7 +2910,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -2969,7 +2969,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3275,7 +3275,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -3429,7 +3429,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -3524,7 +3524,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index d069a3213..0bc121080 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -14,12 +14,12 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/liquidity-layer.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/solver.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: build] ## Full content for each doc page @@ -53,12 +53,12 @@ This section covers Wormhole Settlement, an intent-based solution enabling fast Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. - [:custom-arrow: Discover protocol architectures](/docs/learn/transfers/settlement/architecture/) + [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/architecture/ +Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ --- BEGIN CONTENT --- --- title: Settlement Protocol Architecture @@ -82,7 +82,7 @@ Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster- Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/learn/transfers/settlement/architecture/architecture-1.webp) +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. @@ -124,7 +124,7 @@ First, they lack a competitive price discovery mechanism as limit order prices a Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -![Mayan Swift - Intent-centric design](/docs/images/learn/transfers/settlement/architecture/architecture-2.webp) +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) ### Protocol Flow: How It Works @@ -143,7 +143,7 @@ Mayan Swift addresses these limitations by implementing competitive on-chain Eng Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -![Mayan MCTP diagram](/docs/images/learn/transfers/settlement/architecture/architecture-3.webp) +![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) ### Protocol Flow: How It Works @@ -154,14 +154,14 @@ Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} 3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/build/transfers/settlement/liquidity-layer/){target=\_blank} guide +- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- @@ -210,7 +210,7 @@ Due to the hub-spoke model of liquidity, new chains without proven traction can ## Related Resources -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/learn/transfers/settlement/architecture/){target=\_blank} page +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/transfers/settlement/ @@ -235,7 +235,7 @@ This section provides resources to build with Wormhole Settlement, including int Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. - [:custom-arrow: Build on the Liquidity layer](/docs/build/transfers/settlement/liquidity-layer/) + [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) - :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** @@ -243,12 +243,12 @@ This section provides resources to build with Wormhole Settlement, including int Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - [:custom-arrow: Run a Solver](/docs/build/transfers/settlement/solver/) + [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/faqs/ +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- title: Wormhole Settlement FAQs @@ -273,7 +273,7 @@ After the user receives the token upfront, the execution of additional contract If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/liquidity-layer/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Liquidity Layer @@ -384,7 +384,7 @@ function placeMarketOrder( The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/solver/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Solver @@ -646,11 +646,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -666,7 +666,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -700,14 +700,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -731,7 +731,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -739,7 +739,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -747,9 +747,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -761,7 +761,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -774,7 +774,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -788,12 +788,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -805,17 +805,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -829,7 +829,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -842,7 +842,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -877,7 +877,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -885,13 +885,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -899,7 +899,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -913,7 +913,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -921,12 +921,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -944,7 +944,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -984,11 +984,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -1017,7 +1017,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -1030,7 +1030,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -1042,7 +1042,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -1110,7 +1110,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -1176,7 +1176,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -1184,7 +1184,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -1192,12 +1192,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -1231,7 +1231,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1283,7 +1283,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -1296,7 +1296,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -1308,7 +1308,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -1485,7 +1485,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -1497,7 +1497,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -1505,12 +1505,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -1526,10 +1526,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -1551,7 +1551,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -1570,7 +1570,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -1666,7 +1666,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -1678,7 +1678,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -1743,7 +1743,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -1777,7 +1777,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -1793,15 +1793,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -1945,7 +1945,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -1996,9 +1996,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -2024,7 +2024,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -2135,10 +2135,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -2155,7 +2155,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -2167,18 +2167,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -2196,7 +2196,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -2357,7 +2357,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -2466,7 +2466,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -2489,7 +2489,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -2528,7 +2528,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -2550,7 +2550,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -2591,7 +2591,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -2612,7 +2612,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -2676,7 +2676,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -2696,7 +2696,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -2718,7 +2718,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -2740,7 +2740,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -2748,7 +2748,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -2764,7 +2764,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -2774,12 +2774,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -2910,7 +2910,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -2969,7 +2969,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3275,7 +3275,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -3429,7 +3429,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -3524,7 +3524,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 34976b0e7..2f997387e 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -17,7 +17,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/solidity-sdk.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md [type: build] ## Full content for each doc page @@ -67,7 +67,7 @@ Regardless of which network development environment you are using, there are a f Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC transfers. - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/typescript-sdk/) + [:custom-arrow: Get started with the SDK](/docs/tools/typescript-sdk/get-started/) - :octicons-code-square-16:{ .lg .middle } **Solidity SDK** @@ -75,7 +75,7 @@ Regardless of which network development environment you are using, there are a f Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains. - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/solidity-sdk/) + [:custom-arrow: Get started with the SDK](/docs/tools/solidity-sdk/sdk-reference/) - :octicons-beaker-16:{ .lg .middle } **Tilt** @@ -899,7 +899,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/build/start-building/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -917,7 +917,7 @@ Relying on native tools when possible allows for more rapid prototyping and iter ### Integration -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/build/start-building/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. !!! note Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. @@ -935,7 +935,7 @@ If you'd like to set up a local validator environment, follow the setup guide fo ### Testnet -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: ```text https://api.testnet.wormholescan.io @@ -943,7 +943,7 @@ https://api.testnet.wormholescan.io ### Mainnet -The Mainnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: ```text https://api.wormholescan.io @@ -1000,14 +1000,14 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo 3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/build/reference/contract-addresses/){target=\_blank} section + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/solidity-sdk/ +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ --- BEGIN CONTENT --- --- title: Solidity SDK @@ -1064,7 +1064,7 @@ The Wormhole Solidity SDK consists of key components that streamline cross-chain The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication. -You can refer to the [Wormhole relayer documentation](/docs/build/core-messaging/wormhole-relayers/){target=\_blank} for more details. +You can refer to the [Wormhole relayer documentation](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} for more details. Key modules in the SDK include: @@ -1190,7 +1190,7 @@ abstract contract Base { The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. -For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/build/core-messaging/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: +For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: - **`IWormholeRelayer`** – methods for sending cross-chain messages, VAAs, and token transfers - **`IWormholeReceiver`** – the required implementation for receiving cross-chain messages @@ -1309,7 +1309,7 @@ contract CrossChainTokenReceiver is TokenReceiver { In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. !!! note - Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/build/core-messaging/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. + Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/products/messaging/guides/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. ## Testing Environment @@ -1317,8 +1317,8 @@ The SDK includes built-in support for Forge-based testing, which allows you to t For a detailed example, check out the below repositories: - - [Cross chain messaging](/docs/tutorials/solidity-sdk/cross-chain-contracts/){target=\_blank} - - [Cross chain token transfer](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/){target=\_blank} + - [Cross chain messaging](/docs/products/messaging/tutorials/cross-chain-contracts/){target=\_blank} + - [Cross chain token transfer](/docs/products/messaging/tutorials/cross-chain-token-contracts/){target=\_blank} --- END CONTENT --- ## Basics Concepts [shared: true] @@ -1351,11 +1351,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -1371,7 +1371,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -1405,14 +1405,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -1436,7 +1436,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -1444,7 +1444,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -1452,9 +1452,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -1466,7 +1466,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -1479,7 +1479,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -1493,12 +1493,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -1510,17 +1510,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -1534,7 +1534,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -1547,7 +1547,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -1582,7 +1582,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -1590,13 +1590,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -1604,7 +1604,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -1618,7 +1618,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -1626,12 +1626,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -1649,7 +1649,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -1689,11 +1689,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -1722,7 +1722,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -1735,7 +1735,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -1747,7 +1747,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -1815,7 +1815,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -1881,7 +1881,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -1889,7 +1889,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -1897,12 +1897,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -1936,7 +1936,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1988,7 +1988,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -2001,7 +2001,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -2013,7 +2013,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -2190,7 +2190,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -2202,7 +2202,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -2210,12 +2210,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -2231,10 +2231,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -2256,7 +2256,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2275,7 +2275,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -2371,7 +2371,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -2383,7 +2383,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -2448,7 +2448,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -2482,7 +2482,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -2498,15 +2498,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -2650,7 +2650,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -2701,9 +2701,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -2729,7 +2729,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -2840,10 +2840,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -2860,7 +2860,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -2872,18 +2872,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -2901,7 +2901,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -3062,7 +3062,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -3171,7 +3171,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -3194,7 +3194,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -3233,7 +3233,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -3255,7 +3255,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -3296,7 +3296,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -3317,7 +3317,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -3381,7 +3381,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -3401,7 +3401,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -3423,7 +3423,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -3445,7 +3445,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -3453,7 +3453,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -3469,7 +3469,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -3479,12 +3479,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -3615,7 +3615,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -3674,7 +3674,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3980,7 +3980,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -4134,7 +4134,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -4229,7 +4229,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index ae53d55b7..b1ece10f4 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -32,19 +32,19 @@ Transferring tokens across blockchain networks is challenging due to the lack of Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. ### How Does It Work? -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/learn/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/learn/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. -While the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). ### Token Transfer Flow @@ -81,7 +81,7 @@ One of the key challenges in cross-chain token transfers is maintaining the corr The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. -The [Wormhole Guardian Network](/docs/learn/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. ### Portal Bridge @@ -100,7 +100,7 @@ categories: Token-Bridge, Transfer ## Introduction -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. @@ -108,8 +108,8 @@ This page outlines the core contract methods needed to integrate Token Bridge fu To interact with the Wormhole Token Bridge, you'll need the following: -- [The address of the Token Bridge contract](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers ## How to Interact with Token Bridge Contracts @@ -371,11 +371,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -391,7 +391,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -425,14 +425,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -456,7 +456,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -464,7 +464,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -472,9 +472,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -486,7 +486,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -499,7 +499,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -513,12 +513,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -530,17 +530,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -554,7 +554,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -567,7 +567,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -602,7 +602,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -610,13 +610,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -624,7 +624,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -638,7 +638,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -646,12 +646,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -669,7 +669,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -709,11 +709,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -742,7 +742,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -755,7 +755,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -767,7 +767,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -835,7 +835,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -901,7 +901,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -909,7 +909,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -917,12 +917,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -956,7 +956,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -1008,7 +1008,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -1021,7 +1021,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -1033,7 +1033,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -1210,7 +1210,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -1222,7 +1222,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -1230,12 +1230,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -1251,10 +1251,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -1276,7 +1276,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -1295,7 +1295,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -1391,7 +1391,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -1403,7 +1403,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -1468,7 +1468,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -1502,7 +1502,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -1518,15 +1518,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -1670,7 +1670,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -1721,9 +1721,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -1749,7 +1749,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -1860,10 +1860,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -1880,7 +1880,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -1892,18 +1892,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -1921,7 +1921,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -2082,7 +2082,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -2191,7 +2191,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -2214,7 +2214,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -2253,7 +2253,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -2275,7 +2275,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -2316,7 +2316,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -2337,7 +2337,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -2401,7 +2401,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -2421,7 +2421,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -2443,7 +2443,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -2465,7 +2465,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -2473,7 +2473,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -2489,7 +2489,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -2499,12 +2499,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -2635,7 +2635,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -2694,7 +2694,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3000,7 +3000,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -3154,7 +3154,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -3249,7 +3249,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index d5ada1088..85fe33b74 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -16,46 +16,46 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/architecture.md [type: learn] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md [type: learn] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-data.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-theme.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/features.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/routes.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/upgrade.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/cli-commands.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/access-control.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/rate-limiting.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/troubleshooting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/liquidity-layer.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/solver.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/react-dapp.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] ## Full content for each doc page @@ -156,13 +156,13 @@ While this protocol is wholly separate from Wormhole itself, Wormhole builds on !!! note Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} directly. +You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. ## Automatic Relaying To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank}. +This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. @@ -215,7 +215,7 @@ This section covers Wormhole's Native Token Transfers (NTT), an open source, fle Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. - [:custom-arrow: Discover how NTT works](/docs/learn/transfers/native-token-transfers/architecture/) + [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) - :octicons-book-16:{ .lg .middle } **Deployment Models** @@ -260,7 +260,7 @@ Ready to dive in and start building? Check out the following resources to begin --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/architecture/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- title: Native Token Transfers Architecture @@ -314,10 +314,10 @@ How it works: 2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred 3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain -![NTT architecture diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-1.webp) +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) !!! note - [Learn more](/docs/learn/transfers/native-token-transfers/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. #### Custom Transceivers @@ -325,7 +325,7 @@ The NTT framework supports advanced features such as custom transceivers for spe NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -![Custom Attestation with NTT diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-2.webp) +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. @@ -429,8 +429,8 @@ categories: NTT, Transfer !!!tip "Looking to deploy NTT?" If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/){target=\_blank} + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} ## Introduction @@ -477,12 +477,12 @@ The Token Bridge offers a secure, low-effort integration suitable for applicatio - **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract - **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/learn/security/){target=\_blank} +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} - **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process - **Integration** - straightforward and permissionless method to deploy on multiple chains !!! note - [Learn more](/docs/learn/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. ## Supported Token Standards @@ -551,12 +551,12 @@ This section covers Wormhole Settlement, an intent-based solution enabling fast Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. - [:custom-arrow: Discover protocol architectures](/docs/learn/transfers/settlement/architecture/) + [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/architecture/ +Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ --- BEGIN CONTENT --- --- title: Settlement Protocol Architecture @@ -580,7 +580,7 @@ Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster- Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/learn/transfers/settlement/architecture/architecture-1.webp) +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. @@ -622,7 +622,7 @@ First, they lack a competitive price discovery mechanism as limit order prices a Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -![Mayan Swift - Intent-centric design](/docs/images/learn/transfers/settlement/architecture/architecture-2.webp) +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) ### Protocol Flow: How It Works @@ -641,7 +641,7 @@ Mayan Swift addresses these limitations by implementing competitive on-chain Eng Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -![Mayan MCTP diagram](/docs/images/learn/transfers/settlement/architecture/architecture-3.webp) +![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) ### Protocol Flow: How It Works @@ -652,14 +652,14 @@ Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} 3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/build/transfers/settlement/liquidity-layer/){target=\_blank} guide +- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- @@ -708,7 +708,7 @@ Due to the hub-spoke model of liquidity, new chains without proven traction can ## Related Resources -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/learn/transfers/settlement/architecture/){target=\_blank} page +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page --- END CONTENT --- Doc-Content: https://wormhole.com/docs/learn/transfers/token-bridge/ @@ -725,19 +725,19 @@ Transferring tokens across blockchain networks is challenging due to the lack of Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. ### How Does It Work? -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/learn/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/learn/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. -While the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). ### Token Transfer Flow @@ -774,7 +774,7 @@ One of the key challenges in cross-chain token transfers is maintaining the corr The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. -The [Wormhole Guardian Network](/docs/learn/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. ### Portal Bridge @@ -865,8 +865,8 @@ This guide will walk you through getting started with Wormhole's CCTP contracts To interact with the Wormhole CCTP, you'll need the following: -- [The address of the CCTP contract](/docs/build/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on ## Wormhole's CCTP Integration Contract @@ -877,7 +877,7 @@ The Circle Integration contract emits Wormhole messages with arbitrary payloads This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. !!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/build/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. ??? code "Circle Integration contract" ```solidity @@ -3509,10 +3509,10 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag --- - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/build/start-building/supported-networks/){target=\_blank}. + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - [:custom-arrow: Get started](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - :octicons-tools-16:{ .lg .middle } **Connect FAQs** @@ -3521,7 +3521,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [:custom-arrow: Visit FAQs](/docs/build/transfers/connect/faqs/) + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** @@ -3529,7 +3529,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - [:custom-arrow: Supported Features](/docs/build/transfers/connect/features/) + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) --- END CONTENT --- @@ -3551,9 +3551,9 @@ Wormhole Connect is a flexible React widget that streamlines cross-chain asset t This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. !!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for instructions. + To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/build/transfers/connect/configuration-v0/){target=\_blank}. + If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}.
@@ -3564,7 +3564,7 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - [:custom-arrow: Get started](/docs/build/transfers/connect/configuration/configure-data/) + [:custom-arrow: Get started](/docs/products/connect/configuration/data/) - :octicons-apps-16:{ .lg .middle } **Theme** @@ -3572,12 +3572,12 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. - [:custom-arrow: Explore routes](/docs/build/transfers/connect/configuration/configure-theme/) + [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-data/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- title: Connect Data Configuration @@ -3960,7 +3960,7 @@ function App() { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-theme/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ --- BEGIN CONTENT --- --- title: Connect Theme & UI Customization @@ -4080,7 +4080,7 @@ function App() { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/faqs/ +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ --- BEGIN CONTENT --- --- title: Connect FAQs @@ -4108,7 +4108,7 @@ Connect supports around 30 chains, spanning various blockchain runtimes: - Solana - Move-based chains (Sui, Aptos) -For a complete list of supported chains, see the [Connect-supported chains list](/docs/build/transfers/connect/features/){target=\_blank}. +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## What is gas dropoff? @@ -4154,7 +4154,7 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/features/ +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- title: Features @@ -4201,7 +4201,7 @@ This route appears if both of the following conditions are satisfied: ### Token Bridge Relayer {: #token-bridge-relayer} -On the [routes](/docs/build/transfers/connect/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. @@ -4261,13 +4261,13 @@ The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-d Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -- Multiple ways to bridge assets ([routes](/docs/build/transfers/connect/routes/){target=\_blank}) +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) - Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) - Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer - Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/build/transfers/connect/features/){target=\_blank} at the destination +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/build/transfers/connect/features/){target=\_blank}. +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## Integrate Connect {: #integrate-connect } @@ -4302,7 +4302,7 @@ const container = document.getElementById('bridge-container'); wormholeConnectHosted(container); ``` -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/build/transfers/connect/upgrade/){target=\_blank} guide. +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. ???- code "v0.x" Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. @@ -4337,12 +4337,12 @@ The default configuration of Wormhole Connect may not be exactly what you're loo - Restrict the chains that you allow in your app - Add support for your project's token, and eliminate tokens you don't want to reduce noise - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/build/transfers/connect/routes/){target=\_blank} that are available + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/routes/ +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- title: Routes @@ -4356,7 +4356,7 @@ This page explains the concept of routes in Wormhole Connect. To configure route Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/build/transfers/connect/features/){target=\_blank} to see under which exact conditions the routes appear. +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. ## Token Bridge Routes {: #token-bridge-routes} @@ -4423,7 +4423,7 @@ Note that if native tBTC is transferred out of these chains to any other outside This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/upgrade/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- title: Wormhole Connect v1.0 Migration Guide @@ -5021,7 +5021,7 @@ The process for creating, deploying, and monitoring NTTs is as follows. Select t If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. ## Additional Resources @@ -5033,7 +5033,7 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - [:custom-arrow: NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/) + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - :octicons-question-16:{ .lg .middle } **NTT FAQs** @@ -5041,12 +5041,12 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/cli-commands/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- title: NTT CLI Commands @@ -5117,7 +5117,7 @@ To explore detailed information about any NTT CLI command, including its options Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- @@ -5144,7 +5144,7 @@ This section contains information on configuring Native Token Transfers (NTT), i Discover options for configuring rate limits and how queueing effects transaction flow. - [:custom-arrow: Explore rate limit options](/docs/build/transfers/native-token-transfers/configuration/rate-limiting/) + [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) - :octicons-unlock-16:{ .lg .middle } **Access Control** @@ -5152,12 +5152,12 @@ This section contains information on configuring Native Token Transfers (NTT), i Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. - [:custom-arrow: Explore access control roles](/docs/build/transfers/native-token-transfers/configuration/access-control/) + [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/access-control/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ --- BEGIN CONTENT --- --- title: Native Token Transfers Access Control @@ -5201,7 +5201,7 @@ The `Owner` and the `Pauser` addresses can each pause the contract. Since the co Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/rate-limiting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ --- BEGIN CONTENT --- --- title: Native Token Transfers Rate Limiting @@ -5330,7 +5330,7 @@ This section provides information on installing Wormhole's Native Token Transfer Find information on preparing for NTT deployment to EVM, including an example NTT token repository. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** @@ -5338,7 +5338,7 @@ This section provides information on installing Wormhole's Native Token Transfer Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. - [:custom-arrow: Deploy via Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/) + [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -5346,7 +5346,7 @@ This section provides information on installing Wormhole's Native Token Transfer Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) - :octicons-search-16:{ .lg .middle } **Post Deployment** @@ -5362,12 +5362,12 @@ This section provides information on installing Wormhole's Native Token Transfer Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. - [:custom-arrow: Get help](/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/) + [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- title: Native Token Transfers EVM Deployment @@ -5557,7 +5557,7 @@ By default, NTT transfers to EVM blockchains support automatic relaying via the To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- title: Native Token Transfers Solana Deployment @@ -5667,7 +5667,7 @@ Deploying NTT with the CLI on Solana follows a structured process: Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -By default, NTT transfers to Solana require manual [relaying](/docs/learn/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. ## Set Up NTT @@ -5792,7 +5792,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -5813,7 +5813,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ --- BEGIN CONTENT --- --- title: Deploy Native Token Transfers with Launchpad @@ -5869,11 +5869,11 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Launch a Cross-Chain Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) 3. Set the token details: 1. Select the **home network** from the dropdown menu @@ -5882,22 +5882,22 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 4. Provide the **initial supply** 5. To the token details, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) 4. Select the deployment chains: 1. The home network where your token will be deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -5909,33 +5909,33 @@ Expand an existing token to support NTT across multiple chains. This process int 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Expand Your Existing Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) 3. Enter the token details: 1. Choose the home network where your token is already deployed (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) 4. Select the chains to deploy your token to: 1. The home network where your token is already deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 1. Click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -5945,7 +5945,7 @@ Expand an existing token to support NTT across multiple chains. This process int To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) The dashboard provides a high-level view of your token across all deployed chains, including: @@ -5953,7 +5953,7 @@ The dashboard provides a high-level view of your token across all deployed chain - Supply distribution visualization - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) ## Settings @@ -5968,16 +5968,16 @@ From this section, you can also: - **Pause the token** – temporarily turn off transfers on the selected chain - **Deploy to a new chain** – expand your token by deploying it to an additional chain -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) ### Role Management -This section displays key [roles](/docs/build/transfers/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - **Manager’s Owner** – the owner through the `NTTOwner` proxy - **Pauser** – the address authorized to pause transfers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) ### Security Threshold @@ -5988,7 +5988,7 @@ A higher transceiver threshold increases security by requiring more approvals be - **Registered Transceivers** – displays the number of registered transceivers and their addresses - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) ### Peer Chains Limits @@ -5999,7 +5999,7 @@ Define the transfer restrictions for each connected network. You can adjust: Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/installation/ @@ -6038,7 +6038,7 @@ Follow these steps to install the NTT CLI: ntt --version ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/){target=\_blank} to start using the CLI +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI ## Update NTT CLI @@ -6076,7 +6076,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to EVM chains](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-tools-16:{ .lg .middle } **Deploy to Solana** @@ -6084,7 +6084,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to Solana](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) --- END CONTENT --- @@ -6104,7 +6104,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} allows for a direct integration into your infrastructure +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -6139,7 +6139,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ --- BEGIN CONTENT --- --- title: Troubleshooting NTT Deployment @@ -6151,15 +6151,15 @@ categories: NTT, Transfer If you encounter issues during the NTT deployment process, check the following common points: -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#install-dependencies){target=\_blank} +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain - **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#configure-ntt){target=\_blank} + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} - **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file ???- interface "Dockerfile" @@ -6248,7 +6248,7 @@ If you encounter issues during the NTT deployment process, check the following c ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/faqs/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ --- BEGIN CONTENT --- --- title: Native Token Transfers FAQs @@ -6708,7 +6708,7 @@ This section provides resources to build with Wormhole Settlement, including int Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. - [:custom-arrow: Build on the Liquidity layer](/docs/build/transfers/settlement/liquidity-layer/) + [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) - :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** @@ -6716,12 +6716,12 @@ This section provides resources to build with Wormhole Settlement, including int Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - [:custom-arrow: Run a Solver](/docs/build/transfers/settlement/solver/) + [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/faqs/ +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- title: Wormhole Settlement FAQs @@ -6746,7 +6746,7 @@ After the user receives the token upfront, the execution of additional contract If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/liquidity-layer/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Liquidity Layer @@ -6857,7 +6857,7 @@ function placeMarketOrder( The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/solver/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Solver @@ -7101,7 +7101,7 @@ categories: Token-Bridge, Transfer ## Introduction -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. @@ -7109,8 +7109,8 @@ This page outlines the core contract methods needed to integrate Token Bridge fu To interact with the Wormhole Token Bridge, you'll need the following: -- [The address of the Token Bridge contract](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers ## How to Interact with Token Bridge Contracts @@ -7364,7 +7364,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - [:custom-arrow: Start building](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) @@ -7383,7 +7383,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/connect/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ --- BEGIN CONTENT --- --- title: Integrate Connect into a React DApp Tutorial @@ -7439,7 +7439,7 @@ npm install @wormhole-foundation/wormhole-connect ### Integrate Connect into the Application -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/build/transfers/connect/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: === "JavaScript" @@ -7517,26 +7517,26 @@ To transfer tokens from Sui to Fuji in the Wormhole Connect interface: 2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network 3. Enter the amount of SUI tokens you wish to transfer - ![](/docs/images/tutorials/connect/react-dapp/connect-1.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) 4. Choose to view other routes - ![](/docs/images/tutorials/connect/react-dapp/connect-2.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) 5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) !!! note It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - ![](/docs/images/tutorials/connect/react-dapp/connect-3.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) 6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - ![](/docs/images/tutorials/connect/react-dapp/connect-4.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) 7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - ![](/docs/images/tutorials/connect/react-dapp/connect-5.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. @@ -7544,11 +7544,11 @@ Once the transaction has been submitted, Wormhole Connect will display the progr After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -![](/docs/images/tutorials/connect/react-dapp/connect-6.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. -![](/docs/images/tutorials/connect/react-dapp/connect-7.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) ## Resources @@ -7598,11 +7598,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -7618,7 +7618,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -7652,14 +7652,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -7683,7 +7683,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -7691,7 +7691,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -7699,9 +7699,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -7713,7 +7713,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -7726,7 +7726,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -7740,12 +7740,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -7757,17 +7757,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -7781,7 +7781,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -7794,7 +7794,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -7829,7 +7829,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -7837,13 +7837,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -7851,7 +7851,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -7865,7 +7865,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -7873,12 +7873,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -7896,7 +7896,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -7936,11 +7936,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -7969,7 +7969,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -7982,7 +7982,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -7994,7 +7994,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -8062,7 +8062,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -8128,7 +8128,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -8136,7 +8136,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -8144,12 +8144,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -8183,7 +8183,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -8235,7 +8235,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -8248,7 +8248,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -8260,7 +8260,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -8437,7 +8437,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -8449,7 +8449,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -8457,12 +8457,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -8478,10 +8478,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -8503,7 +8503,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -8522,7 +8522,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -8618,7 +8618,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -8630,7 +8630,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -8695,7 +8695,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -8729,7 +8729,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -8745,15 +8745,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -8897,7 +8897,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -8948,9 +8948,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -8976,7 +8976,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -9087,10 +9087,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -9107,7 +9107,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -9119,18 +9119,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -9148,7 +9148,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -9309,7 +9309,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -9418,7 +9418,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -9441,7 +9441,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -9480,7 +9480,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -9502,7 +9502,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -9543,7 +9543,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -9564,7 +9564,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -9628,7 +9628,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -9648,7 +9648,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -9670,7 +9670,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -9692,7 +9692,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -9700,7 +9700,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -9716,7 +9716,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -9726,12 +9726,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -9862,7 +9862,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -9921,7 +9921,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -10227,7 +10227,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -10381,7 +10381,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -10476,7 +10476,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 422b1daf6..06956c158 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -17,10 +17,10 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md [type: build] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/protocols-payloads.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/sdk-layout.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/vaas-protocols.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/wormhole-sdk.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md [type: build] ## Full content for each doc page @@ -803,7 +803,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/build/start-building/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -821,7 +821,7 @@ Relying on native tools when possible allows for more rapid prototyping and iter ### Integration -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/build/start-building/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. !!! note Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. @@ -839,7 +839,7 @@ If you'd like to set up a local validator environment, follow the setup guide fo ### Testnet -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: ```text https://api.testnet.wormholescan.io @@ -847,7 +847,7 @@ https://api.testnet.wormholescan.io ### Mainnet -The Mainnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: ```text https://api.wormholescan.io @@ -904,7 +904,7 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo 3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/build/reference/contract-addresses/){target=\_blank} section + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field @@ -933,7 +933,7 @@ The Wormhole SDK provides developers with essential tools for cross-chain commun Learn about the core functionalities of the Wormhole SDK, including how to use its features for building cross-chain applications. - [:custom-arrow: Explore the SDK](/docs/build/toolkit/typescript-sdk/wormhole-sdk/) + [:custom-arrow: Explore the SDK](/docs/tools/typescript-sdk/sdk-reference/) - :octicons-code-16:{ .lg .middle } **Layouts** @@ -941,12 +941,12 @@ The Wormhole SDK provides developers with essential tools for cross-chain commun Discover how to define, serialize, and deserialize data structures using the Wormhole SDK's layout system, ensuring efficient cross-chain communication. - [:custom-arrow: Learn about layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/) + [:custom-arrow: Learn about layouts](/docs/tools/typescript-sdk/guides/sdk-layout/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/protocols-payloads/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ --- BEGIN CONTENT --- --- title: Building Protocols and Payloads @@ -1131,7 +1131,7 @@ This implementation ensures dynamic, efficient handling of payloads at runtime. ## Integrate Protocols with Payloads -Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank}. +Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}. ### Payload Discriminators @@ -1267,7 +1267,7 @@ While this guide focuses on the `TokenBridge` protocol, other protocols, like NT For more details, you can explore the [NTT implementation in the SDK](https://github.com/wormhole-foundation/example-native-token-transfers/blob/00f83aa215338b1b8fd66f522bd0f45be3e98a5a/sdk/definitions/src/ntt.ts){target=\_blank}. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/sdk-layout/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/sdk-layout/ --- BEGIN CONTENT --- --- title: Data Layouts @@ -1697,7 +1697,7 @@ VAAs are the backbone of Wormhole’s cross-chain communication. Each VAA is a s The Wormhole SDK organizes the VAA structure into three key components: - [**Header**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L37-L41){target=\_blank} - contains metadata such as the Guardian set index and an array of Guardian signatures - - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} + - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} - **Payload** - provides application-specific data, such as the actual message or operation being performed **Header layout:** @@ -1859,7 +1859,7 @@ return { In the Wormhole SDK, payloads rely on layouts to define their binary structure, ensuring consistency and type safety across protocols. Custom payloads extend this functionality, allowing developers to handle protocol-specific features or unique use cases. -To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} page for a detailed guide. +To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} page for a detailed guide. ## Common Pitfalls & Best Practices @@ -1981,7 +1981,7 @@ For further learning and practical experience, explore the following resources: - **Layout tests repository** - for hands-on experimentation, check out this [layout package repository](https://github.com/nonergodic/layout){target=\_blank}, which provides examples and unit tests to help you better understand serialization, deserialization, and the strong typing mechanism. Running these tests locally is a great way to deepen your understanding of how layouts function in real-world scenarios --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/vaas-protocols/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/vaas-protocols/ --- BEGIN CONTENT --- --- title: VAAs and Protocols @@ -1993,12 +1993,12 @@ categories: Typescript-SDK ## Introduction -Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. +Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. For deeper insights into serialization, deserialization, and protocol design, refer to: -- [Data Layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank} for serialization concepts -- [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} for designing custom protocol messages +- [Data Layouts](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank} for serialization concepts +- [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} for designing custom protocol messages This guide will help you understand how to handle VAAs and protocol messages in off-chain and on-chain scenarios. @@ -2039,7 +2039,7 @@ Each protocol integrates its payload format into the VAA structure, ensuring con The TypeScript SDK is designed for off-chain operations like reading, validating, and manipulating VAAs before submitting them to a chain. Developers can easily deserialize VAAs to extract protocol payloads and prepare actions such as initiating token transfers or constructing delivery instructions. -In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank}: +In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank}: ```typescript import { deserializeLayout } from '@wormhole-foundation/sdk-base'; @@ -2102,7 +2102,7 @@ contract EnvelopeParser { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/wormhole-sdk/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/sdk-reference/ --- BEGIN CONTENT --- --- title: Wormhole TS SDK @@ -2612,7 +2612,7 @@ The code then prepares a message for publication. This message includes: - The sender's address - The message payload (in this case, the encoded string `lol`) - A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. @@ -3538,11 +3538,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -3558,7 +3558,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -3592,14 +3592,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -3623,7 +3623,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -3631,7 +3631,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -3639,9 +3639,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -3653,7 +3653,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -3666,7 +3666,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -3680,12 +3680,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -3697,17 +3697,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -3721,7 +3721,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -3734,7 +3734,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -3769,7 +3769,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -3777,13 +3777,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -3791,7 +3791,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -3805,7 +3805,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -3813,12 +3813,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -3836,7 +3836,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -3876,11 +3876,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -3909,7 +3909,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -3922,7 +3922,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -3934,7 +3934,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -4002,7 +4002,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -4068,7 +4068,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -4076,7 +4076,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -4084,12 +4084,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -4123,7 +4123,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -4175,7 +4175,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -4188,7 +4188,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -4200,7 +4200,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -4377,7 +4377,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -4389,7 +4389,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -4397,12 +4397,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -4418,10 +4418,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -4443,7 +4443,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -4462,7 +4462,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -4558,7 +4558,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -4570,7 +4570,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -4635,7 +4635,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -4669,7 +4669,7 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -4685,15 +4685,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -4837,7 +4837,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -4888,9 +4888,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -4916,7 +4916,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -5027,10 +5027,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -5047,7 +5047,7 @@ For a deeper understanding of the Core Contract implementation for a specific bl - [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -5059,18 +5059,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -5088,7 +5088,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -5249,7 +5249,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/start-building/products/ @@ -5358,7 +5358,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -5381,7 +5381,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -5420,7 +5420,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -5442,7 +5442,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -5483,7 +5483,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -5504,7 +5504,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -5568,7 +5568,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -5588,7 +5588,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -5610,7 +5610,7 @@ While it may not be required for all use cases, it offers a deeper technical lay ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -5632,7 +5632,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -5640,7 +5640,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -5656,7 +5656,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -5666,12 +5666,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -5802,7 +5802,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -5861,7 +5861,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -6167,7 +6167,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -6321,7 +6321,7 @@ For cross-chain dApp development, Wormhole formatted addresses simplify handling Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -6416,7 +6416,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets diff --git a/llms-full.txt b/llms-full.txt index 11367011d..93f646411 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -6,123 +6,123 @@ Wormhole. A cross-chain messaging protocol used to move data and assets between Documentation: https://wormhole.com/docs/ ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/core-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/wormhole-relayers.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/run-spy.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-evm.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-solana.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/faq.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-evm.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-solana.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/chain-ids.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/consistency-levels.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/contract-addresses.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/wormhole-formatted-addresses.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/supported-networks.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/testnet-faucets.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/solidity-sdk.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/protocols-payloads.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/sdk-layout.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/vaas-protocols.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/wormhole-sdk.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration-v0.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-data.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-theme.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/features.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/routes.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/upgrade.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/cli-commands.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/access-control.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/rate-limiting.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/troubleshooting.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/liquidity-layer.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/solver.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/architecture.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/faq.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/architecture.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/core-contracts.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/guardians.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/relayer.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/spy.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/vaas.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/introduction.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/security.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/react-dapp.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/multichain-token.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/treasury-proposal.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.settlement-routes.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/cross-chain-contracts.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/cross-chain-token-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/tokens-via-token-bridge.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/usdc-via-cctp.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/replace-signatures.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/core-messaging/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- title: Get Started with Core Contracts @@ -138,15 +138,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -290,7 +290,7 @@ messageSequence = wormhole.publishMessage{value: wormholeFee}( `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -341,9 +341,9 @@ wormhole::post_message( View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -369,7 +369,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -480,10 +480,10 @@ await tx.wait(); #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. @@ -516,7 +516,7 @@ Follow the links below for how-to guides about using Core Contracts and Wormhole ## Simplified Message Flow -Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/build/start-building/supported-networks/){target=\_blank} page. +Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. [timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] @@ -530,7 +530,7 @@ Wormhole-deployed relayer support is limited to EVM environments. For a complete Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. - [:custom-arrow: Get started](/docs/build/core-messaging/core-contracts/#prerequisites) + [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) - :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** @@ -538,12 +538,12 @@ Wormhole-deployed relayer support is limited to EVM environments. For a complete Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. - [:custom-arrow: Get started](/docs/build/core-messaging/wormhole-relayers/#get-started-with-the-wormhole-relayer) + [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/wormhole-relayers/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- title: Wormhole-Deployed Relayers @@ -555,18 +555,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -584,7 +584,7 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: @@ -745,7 +745,7 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/ @@ -762,15 +762,15 @@ template: root-index-page.html If you learn best by building, start here to build with the Wormhole TypeScript SDK: -- [**Transfer Tokens via the Token Bridge**](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/){target=\_blank} - use the [Wormhole SDK's](/docs/build/toolkit/typescript-sdk/){target=\_blank} Token Bridge method to move wrapped assets across networks +- [**Transfer Tokens via the Token Bridge**](/docs/products/token-bridge/tutorials/transfer-workflow/){target=\_blank} - use the [Wormhole SDK's](/docs/tools/typescript-sdk/get-started/){target=\_blank} Token Bridge method to move wrapped assets across networks -- [**Transfer USDC via CCTP and Wormhole SDK**](/docs/tutorials/typescript-sdk/usdc-via-cctp/){target=\_blank} - combine the [Wormhole SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} and Circle's Cross-Chain Transfer Protocol (CCTP) to bridge native USDC across networks +- [**Transfer USDC via CCTP and Wormhole SDK**](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/){target=\_blank} - combine the [Wormhole SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} and Circle's Cross-Chain Transfer Protocol (CCTP) to bridge native USDC across networks Alternatively, start here to work with Wormhole contracts directly: -- [**Create Multichain Messaging Contracts**](/docs/tutorials/solidity-sdk/cross-chain-contracts/) - create mulitchain contracts using Wormhole's Solidity SDK. You will deploy smart contracts and send messages across chains +- [**Create Multichain Messaging Contracts**](/docs/products/messaging/tutorials/cross-chain-contracts/) - create mulitchain contracts using Wormhole's Solidity SDK. You will deploy smart contracts and send messages across chains -- [**Create Multichain Token Transfer Contracts**](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) - create multichain token transfers using Wormhole's Solidity SDK. You will build and deploy smart contracts to send tokens from one blockchain to another +- [**Create Multichain Token Transfer Contracts**](/docs/products/messaging/tutorials/cross-chain-token-contracts/) - create multichain token transfers using Wormhole's Solidity SDK. You will build and deploy smart contracts to send tokens from one blockchain to another ## Builder Essentials @@ -784,7 +784,7 @@ Access essential information and tools quickly: Supported blockchains by environment - main or testnet availability and quick links to the website, documentation, and block explorer for each network. - [:custom-arrow: Supported Networks](/docs/build/start-building/supported-networks/) + [:custom-arrow: Supported Networks](/docs/products/reference/supported-networks/) - :octicons-tools-16:{ .lg .middle } **Testnet Faucets** @@ -792,7 +792,7 @@ Access essential information and tools quickly: Links to testnet token faucets for supported networks. - [:custom-arrow: Get Testnet Tokens](/docs/build/start-building/testnet-faucets/) + [:custom-arrow: Get Testnet Tokens](/docs/products/reference/testnet-faucets/) - :octicons-tools-16:{ .lg .middle } **Wormhole TypeScript SDK** @@ -800,7 +800,7 @@ Access essential information and tools quickly: Your guide to Wormhole SDK installation and usage, concepts overview, and code samples. - [:custom-arrow: Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/wormhole-sdk/) + [:custom-arrow: Wormhole TypeScript SDK](/docs/tools/typescript-sdk/sdk-reference/) - :octicons-tools-16:{ .lg .middle } **Reference** @@ -808,7 +808,7 @@ Access essential information and tools quickly: Wormhole chain ID, contract address, address formatting and conversion, and consistency information. - [:custom-arrow: Reference](/docs/build/reference/) + [:custom-arrow: Reference](/docs/products/reference/) @@ -884,7 +884,7 @@ Follow the guides in this section to learn how to run off-chain infrastructure s Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. - [:custom-arrow: Run a relayer](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Run a relayer](/docs/protocol/infrastructure-guides/run-relayer/) @@ -896,7 +896,7 @@ Follow the guides in this section to learn how to run off-chain infrastructure s Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. - [:custom-arrow: Run a Spy](/docs/infrastructure/spy/run-spy/) + [:custom-arrow: Run a Spy](/docs/protocol/infrastructure-guides/run-spy/) --- END CONTENT --- @@ -938,7 +938,7 @@ categories: Relayers
- [:custom-arrow: Get started now](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-relayer/) @@ -952,7 +952,7 @@ categories: Relayers Learn about what a relayer is, what role it plays in the delivery of cross-chain messages, and the different types of relayers in the Wormhole ecosystem. - [:custom-arrow: Learn more about relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn more about relayers](/docs/protocol/infrastructure/relayer/) - :octicons-gear-16:{ .lg .middle } **Simplify the Development Process** @@ -965,7 +965,7 @@ categories: Relayers --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/infrastructure/relayers/run-relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ --- BEGIN CONTENT --- --- title: Run a Relayer @@ -990,7 +990,7 @@ This guide teaches you how to set up and configure a custom relayer for efficien To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs.
- ![Custom relayer](/docs/images/build/infrastructure/relayers/run-relayer/relayer-1.webp) + ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp)
The off-chain components outlined in blue must be implemented.
@@ -1131,7 +1131,7 @@ The source code for this example is available in the [`relayer-engine` repositor Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. -More details about the Spy are available in the [Spy Documentation](/docs/learn/infrastructure/spy){target=\_blank}. +More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. ### Wormhole Network Spy @@ -1312,7 +1312,7 @@ description: Discover everything you need to about the Wormhole Spy, a daemon th The content in this section shows you how you can run your own infrastructure and spin up a Spy daemon locally to subscribe to a stream of messages, also known as Verifiable Action Approvals (VAAs). - [:custom-arrow: Get started now](/docs/infrastructure/spy/run-spy/) + [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-spy/) @@ -1326,7 +1326,7 @@ description: Discover everything you need to about the Wormhole Spy, a daemon th Learn about what a Spy is and what role it plays in the delivery of cross-chain messages. - [:custom-arrow: Learn more about Spies](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn more about Spies](/docs/protocol/infrastructure/spy/) - :octicons-code-16:{ .lg .middle } **Interact with a Spy** @@ -1347,7 +1347,7 @@ description: Discover everything you need to about the Wormhole Spy, a daemon th --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/infrastructure/spy/run-spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-spy/ --- BEGIN CONTENT --- --- title: Run a Spy @@ -1360,7 +1360,7 @@ description: Learn how to run a Spy locally to listen for and forward messages ( The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. -For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/learn/infrastructure/spy/){target=\_blank}. +For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. ## How to Start a Spy @@ -1431,7 +1431,7 @@ The Spy does not have a built-in persistence layer, so it is typically paired wi The persistence layer needs to implement the appropriate interface. For example, you can check out the [Redis interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank} used by the Relayer Engine, a package that implements a client and persistence layer for messages received from a Spy subscription. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- title: Deploy MultiGov on EVM Chains @@ -1537,7 +1537,7 @@ These parameters can be queried using their respective getter functions on the a To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- title: MultiGov Deployment to Solana @@ -1547,7 +1547,7 @@ categories: MultiGov # Deploy MultiGov on Solana -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/learn/governance/architecture/){target=\_blank}. +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. @@ -1727,7 +1727,7 @@ When deploying MultiGov on Solana, several key parameters need to be set. Here a - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/faq/ +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ --- BEGIN CONTENT --- --- title: MultiGov Technical FAQs @@ -1750,7 +1750,7 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl ### Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/build/start-building/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. ### How are votes aggregated across different chains? @@ -1849,7 +1849,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -1857,7 +1857,7 @@ Take the following steps to get started with a MultiGov integration: Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** @@ -1865,7 +1865,7 @@ Take the following steps to get started with a MultiGov integration: Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/build/multigov/upgrade-evm/) + [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** @@ -1873,7 +1873,7 @@ Take the following steps to get started with a MultiGov integration: Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/build/multigov/upgrade-solana/) + [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - :octicons-question-16:{ .lg .middle } **Technical FAQs** @@ -1881,7 +1881,7 @@ Take the following steps to get started with a MultiGov integration: Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) @@ -1908,7 +1908,7 @@ Take the following steps to get started with a MultiGov integration: --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/upgrade-evm/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ --- BEGIN CONTENT --- --- title: Upgrading MultiGov on EVM @@ -1978,7 +1978,7 @@ MultiGov is designed to be flexible but stable. Due to the system's complexity a - Always test upgrades extensively on testnets before implementing in production --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/multigov/upgrade-solana/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ --- BEGIN CONTENT --- --- title: Upgrading MultiGov on Solana @@ -2049,7 +2049,7 @@ Follow these steps to upgrade the MultiGov Staking Program on Solana: ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/queries/faqs/ +Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- title: Queries FAQs @@ -2141,7 +2141,7 @@ Wormhole Queries offers on-demand access to Guardian-attested on-chain data via Explore frequently asked questions about Wormhole Queries. - [:custom-arrow: Check out the FAQs](/docs/build/queries/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/queries/faqs/) --- END CONTENT --- @@ -2240,7 +2240,7 @@ For example, many chains have implementations forked from [Geth](https://github. Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. -Be sure to check out the [FAQs](/docs/build/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. +Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. You can also check out the following examples of applications that make use of Wormhole Queries: @@ -2464,7 +2464,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe @@ -2671,7 +2671,7 @@ const tx = await contract.updateCounters( ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- title: Chain IDs @@ -2802,7 +2802,7 @@ The following table documents the chain IDs used by Wormhole and places them alo --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ --- BEGIN CONTENT --- --- title: Wormhole Finality | Consistency Levels @@ -2861,7 +2861,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/contract-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- title: Contract Addresses @@ -3167,7 +3167,7 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/ +Doc-Content: https://wormhole.com/docs/products/reference/ --- BEGIN CONTENT --- --- title: Reference @@ -3189,7 +3189,7 @@ In this section, you'll find reference information that is essential for develop Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - [:custom-arrow: View list of chain IDs](/docs/build/reference/chain-ids/) + [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - :material-timer-sand:{ .lg .middle } **Wormhole Finality** @@ -3197,7 +3197,7 @@ In this section, you'll find reference information that is essential for develop See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - [:custom-arrow: View list of finality levels](/docs/build/reference/consistency-levels/) + [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - :octicons-file-code-16:{ .lg .middle } **Contract Addresses** @@ -3213,7 +3213,7 @@ In this section, you'll find reference information that is essential for develop - Wormhole relayer - CCTP - [:custom-arrow: View list of contract addresses](/docs/build/reference/contract-addresses/) + [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** @@ -3223,12 +3223,12 @@ In this section, you'll find reference information that is essential for develop This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - [:custom-arrow: View details on Wormhole formatted addresses](/docs/build/reference/wormhole-formatted-addresses/) + [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/reference/wormhole-formatted-addresses/ +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ --- BEGIN CONTENT --- --- title: Wormhole Formatted Addresses @@ -3417,7 +3417,7 @@ Wormhole's role as a Generic Message Passing (GMP) protocol means it facilitates Explore the blockchains supported by Wormhole for cross-chain communication and asset transfers. Understand which networks are available for both Testnet and Mainnet environments. - [:custom-arrow: Discover supported networks](/docs/build/start-building/supported-networks/) + [:custom-arrow: Discover supported networks](/docs/products/reference/supported-networks/) - :octicons-goal-16:{ .lg .middle } **Testnet Faucets** @@ -3425,7 +3425,7 @@ Wormhole's role as a Generic Message Passing (GMP) protocol means it facilitates Get Testnet tokens to start experimenting with cross-chain transfers and contract deployment. - [:custom-arrow: Find Testnet faucets](/docs/build/start-building/testnet-faucets/) + [:custom-arrow: Find Testnet faucets](/docs/products/reference/testnet-faucets/) - :octicons-list-unordered-16:{ .lg .middle } **Reference** @@ -3433,7 +3433,7 @@ Wormhole's role as a Generic Message Passing (GMP) protocol means it facilitates Access the essential Wormhole chain IDs and smart contract addresses for messaging protocols, token bridges, and other key components. - [:custom-arrow: Explore Reference](/docs/build/reference/){target=\_blank} + [:custom-arrow: Explore Reference](/docs/products/reference/){target=\_blank} --- END CONTENT --- @@ -3500,7 +3500,7 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/supported-networks/ +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks @@ -3595,7 +3595,7 @@ Wormhole supports several different blockchains and environments. Since many of --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- title: Testnet Faucets @@ -3727,7 +3727,7 @@ Let users borrow assets on one chain using collateral from another. 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time @@ -3750,7 +3750,7 @@ Fetch price feeds across multiple chains for DeFi applications. 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – sends signals to execute trades +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades 🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} @@ -3789,7 +3789,7 @@ Enable seamless communication and asset transfer across decentralized social net 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions - [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards 🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} @@ -3811,7 +3811,7 @@ Launch and distribute memecoins across multiple chains, enabling cross-chain fun 🛠 **Wormhole products used:** - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems @@ -3852,7 +3852,7 @@ Allow users to pay gas fees with any token across different networks, removing f 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements @@ -3873,7 +3873,7 @@ Provide developers with a library of bridging intents and automation functions, 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents 🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries @@ -3937,7 +3937,7 @@ Fetch and verify cross-chain data, enabling reliable, decentralized Oracle servi 🛠 **Wormhole products used:** - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks 🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} @@ -3957,7 +3957,7 @@ Enable users to stake assets on one chain while earning rewards or securing netw 🛠 **Wormhole products used:** -- [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} @@ -4745,7 +4745,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/build/start-building/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -4763,7 +4763,7 @@ Relying on native tools when possible allows for more rapid prototyping and iter ### Integration -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/build/start-building/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. !!! note Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. @@ -4781,7 +4781,7 @@ If you'd like to set up a local validator environment, follow the setup guide fo ### Testnet -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: ```text https://api.testnet.wormholescan.io @@ -4789,7 +4789,7 @@ https://api.testnet.wormholescan.io ### Mainnet -The Mainnet contract addresses are available on the page for each [environment](/docs/build/start-building/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: ```text https://api.wormholescan.io @@ -4846,7 +4846,7 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo 3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/build/reference/contract-addresses/){target=\_blank} section + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field @@ -4899,7 +4899,7 @@ Regardless of which network development environment you are using, there are a f Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC transfers. - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/typescript-sdk/) + [:custom-arrow: Get started with the SDK](/docs/tools/typescript-sdk/get-started/) - :octicons-code-square-16:{ .lg .middle } **Solidity SDK** @@ -4907,7 +4907,7 @@ Regardless of which network development environment you are using, there are a f Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains. - [:custom-arrow: Get started with the SDK](/docs/build/toolkit/solidity-sdk/) + [:custom-arrow: Get started with the SDK](/docs/tools/solidity-sdk/sdk-reference/) - :octicons-beaker-16:{ .lg .middle } **Tilt** @@ -4952,7 +4952,7 @@ Regardless of which network development environment you are using, there are a f --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/solidity-sdk/ +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ --- BEGIN CONTENT --- --- title: Solidity SDK @@ -5009,7 +5009,7 @@ The Wormhole Solidity SDK consists of key components that streamline cross-chain The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication. -You can refer to the [Wormhole relayer documentation](/docs/build/core-messaging/wormhole-relayers/){target=\_blank} for more details. +You can refer to the [Wormhole relayer documentation](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} for more details. Key modules in the SDK include: @@ -5135,7 +5135,7 @@ abstract contract Base { The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. -For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/build/core-messaging/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: +For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: - **`IWormholeRelayer`** – methods for sending cross-chain messages, VAAs, and token transfers - **`IWormholeReceiver`** – the required implementation for receiving cross-chain messages @@ -5254,7 +5254,7 @@ contract CrossChainTokenReceiver is TokenReceiver { In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. !!! note - Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/build/core-messaging/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. + Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/products/messaging/guides/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. ## Testing Environment @@ -5262,8 +5262,8 @@ The SDK includes built-in support for Forge-based testing, which allows you to t For a detailed example, check out the below repositories: - - [Cross chain messaging](/docs/tutorials/solidity-sdk/cross-chain-contracts/){target=\_blank} - - [Cross chain token transfer](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/){target=\_blank} + - [Cross chain messaging](/docs/products/messaging/tutorials/cross-chain-contracts/){target=\_blank} + - [Cross chain token transfer](/docs/products/messaging/tutorials/cross-chain-token-contracts/){target=\_blank} --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/ @@ -5288,7 +5288,7 @@ The Wormhole SDK provides developers with essential tools for cross-chain commun Learn about the core functionalities of the Wormhole SDK, including how to use its features for building cross-chain applications. - [:custom-arrow: Explore the SDK](/docs/build/toolkit/typescript-sdk/wormhole-sdk/) + [:custom-arrow: Explore the SDK](/docs/tools/typescript-sdk/sdk-reference/) - :octicons-code-16:{ .lg .middle } **Layouts** @@ -5296,12 +5296,12 @@ The Wormhole SDK provides developers with essential tools for cross-chain commun Discover how to define, serialize, and deserialize data structures using the Wormhole SDK's layout system, ensuring efficient cross-chain communication. - [:custom-arrow: Learn about layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/) + [:custom-arrow: Learn about layouts](/docs/tools/typescript-sdk/guides/sdk-layout/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/protocols-payloads/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ --- BEGIN CONTENT --- --- title: Building Protocols and Payloads @@ -5486,7 +5486,7 @@ This implementation ensures dynamic, efficient handling of payloads at runtime. ## Integrate Protocols with Payloads -Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank}. +Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}. ### Payload Discriminators @@ -5622,7 +5622,7 @@ While this guide focuses on the `TokenBridge` protocol, other protocols, like NT For more details, you can explore the [NTT implementation in the SDK](https://github.com/wormhole-foundation/example-native-token-transfers/blob/00f83aa215338b1b8fd66f522bd0f45be3e98a5a/sdk/definitions/src/ntt.ts){target=\_blank}. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/sdk-layout/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/sdk-layout/ --- BEGIN CONTENT --- --- title: Data Layouts @@ -6052,7 +6052,7 @@ VAAs are the backbone of Wormhole’s cross-chain communication. Each VAA is a s The Wormhole SDK organizes the VAA structure into three key components: - [**Header**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L37-L41){target=\_blank} - contains metadata such as the Guardian set index and an array of Guardian signatures - - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} + - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} - **Payload** - provides application-specific data, such as the actual message or operation being performed **Header layout:** @@ -6214,7 +6214,7 @@ return { In the Wormhole SDK, payloads rely on layouts to define their binary structure, ensuring consistency and type safety across protocols. Custom payloads extend this functionality, allowing developers to handle protocol-specific features or unique use cases. -To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} page for a detailed guide. +To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} page for a detailed guide. ## Common Pitfalls & Best Practices @@ -6336,7 +6336,7 @@ For further learning and practical experience, explore the following resources: - **Layout tests repository** - for hands-on experimentation, check out this [layout package repository](https://github.com/nonergodic/layout){target=\_blank}, which provides examples and unit tests to help you better understand serialization, deserialization, and the strong typing mechanism. Running these tests locally is a great way to deepen your understanding of how layouts function in real-world scenarios --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/vaas-protocols/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/vaas-protocols/ --- BEGIN CONTENT --- --- title: VAAs and Protocols @@ -6348,12 +6348,12 @@ categories: Typescript-SDK ## Introduction -Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. +Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. For deeper insights into serialization, deserialization, and protocol design, refer to: -- [Data Layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank} for serialization concepts -- [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} for designing custom protocol messages +- [Data Layouts](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank} for serialization concepts +- [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} for designing custom protocol messages This guide will help you understand how to handle VAAs and protocol messages in off-chain and on-chain scenarios. @@ -6394,7 +6394,7 @@ Each protocol integrates its payload format into the VAA structure, ensuring con The TypeScript SDK is designed for off-chain operations like reading, validating, and manipulating VAAs before submitting them to a chain. Developers can easily deserialize VAAs to extract protocol payloads and prepare actions such as initiating token transfers or constructing delivery instructions. -In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank}: +In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank}: ```typescript import { deserializeLayout } from '@wormhole-foundation/sdk-base'; @@ -6457,7 +6457,7 @@ contract EnvelopeParser { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/wormhole-sdk/ +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/sdk-reference/ --- BEGIN CONTENT --- --- title: Wormhole TS SDK @@ -6967,7 +6967,7 @@ The code then prepares a message for publication. This message includes: - The sender's address - The message payload (in this case, the encoded string `lol`) - A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. @@ -7885,8 +7885,8 @@ This guide will walk you through getting started with Wormhole's CCTP contracts To interact with the Wormhole CCTP, you'll need the following: -- [The address of the CCTP contract](/docs/build/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on ## Wormhole's CCTP Integration Contract @@ -7897,7 +7897,7 @@ The Circle Integration contract emits Wormhole messages with arbitrary payloads This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. !!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/build/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. ??? code "Circle Integration contract" ```solidity @@ -10487,7 +10487,7 @@ function receivePayloadAndUSDC( To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration-v0/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/configuration-v0/ --- BEGIN CONTENT --- --- title: Configure Your Connect Widget v0 @@ -10503,7 +10503,7 @@ Wormhole Connect is a flexible React widget that streamlines cross-chain asset t This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. !!! note - For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/build/transfers/connect/configuration/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for detailed instructions. + For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/build/transfers/connect/configuration/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. ## Get Started @@ -11218,7 +11218,7 @@ Enable the explorer button to allow users to search for their transactions on a | `target` | `href` target. Defaults to `_blank` | --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-data/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- title: Connect Data Configuration @@ -11601,7 +11601,7 @@ function App() { ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/configure-theme/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ --- BEGIN CONTENT --- --- title: Connect Theme & UI Customization @@ -11738,9 +11738,9 @@ Wormhole Connect is a flexible React widget that streamlines cross-chain asset t This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. !!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for instructions. + To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/build/transfers/connect/configuration-v0/){target=\_blank}. + If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}.
@@ -11751,7 +11751,7 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - [:custom-arrow: Get started](/docs/build/transfers/connect/configuration/configure-data/) + [:custom-arrow: Get started](/docs/products/connect/configuration/data/) - :octicons-apps-16:{ .lg .middle } **Theme** @@ -11759,12 +11759,12 @@ This guide provides detailed instructions on configuring Wormhole Connect and hi Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. - [:custom-arrow: Explore routes](/docs/build/transfers/connect/configuration/configure-theme/) + [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/faqs/ +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ --- BEGIN CONTENT --- --- title: Connect FAQs @@ -11792,7 +11792,7 @@ Connect supports around 30 chains, spanning various blockchain runtimes: - Solana - Move-based chains (Sui, Aptos) -For a complete list of supported chains, see the [Connect-supported chains list](/docs/build/transfers/connect/features/){target=\_blank}. +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## What is gas dropoff? @@ -11838,7 +11838,7 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/features/ +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- title: Features @@ -11885,7 +11885,7 @@ This route appears if both of the following conditions are satisfied: ### Token Bridge Relayer {: #token-bridge-relayer} -On the [routes](/docs/build/transfers/connect/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. @@ -11967,10 +11967,10 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag --- - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/build/start-building/supported-networks/){target=\_blank}. + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - [:custom-arrow: Get started](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - :octicons-tools-16:{ .lg .middle } **Connect FAQs** @@ -11979,7 +11979,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [:custom-arrow: Visit FAQs](/docs/build/transfers/connect/faqs/) + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** @@ -11987,7 +11987,7 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - [:custom-arrow: Supported Features](/docs/build/transfers/connect/features/) + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) --- END CONTENT --- @@ -12012,13 +12012,13 @@ The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-d Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -- Multiple ways to bridge assets ([routes](/docs/build/transfers/connect/routes/){target=\_blank}) +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) - Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) - Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer - Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/build/transfers/connect/features/){target=\_blank} at the destination +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/build/transfers/connect/features/){target=\_blank}. +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## Integrate Connect {: #integrate-connect } @@ -12053,7 +12053,7 @@ const container = document.getElementById('bridge-container'); wormholeConnectHosted(container); ``` -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/build/transfers/connect/upgrade/){target=\_blank} guide. +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. ???- code "v0.x" Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. @@ -12088,12 +12088,12 @@ The default configuration of Wormhole Connect may not be exactly what you're loo - Restrict the chains that you allow in your app - Add support for your project's token, and eliminate tokens you don't want to reduce noise - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/build/transfers/connect/routes/){target=\_blank} that are available + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/routes/ +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- title: Routes @@ -12107,7 +12107,7 @@ This page explains the concept of routes in Wormhole Connect. To configure route Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/build/transfers/connect/features/){target=\_blank} to see under which exact conditions the routes appear. +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. ## Token Bridge Routes {: #token-bridge-routes} @@ -12174,7 +12174,7 @@ Note that if native tBTC is transferred out of these chains to any other outside This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/upgrade/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- title: Wormhole Connect v1.0 Migration Guide @@ -12829,7 +12829,7 @@ While all of these products handle token transfers, there are additional feature --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/cli-commands/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- title: NTT CLI Commands @@ -12900,12 +12900,12 @@ To explore detailed information about any NTT CLI command, including its options Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/access-control/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ --- BEGIN CONTENT --- --- title: Native Token Transfers Access Control @@ -12971,7 +12971,7 @@ This section contains information on configuring Native Token Transfers (NTT), i Discover options for configuring rate limits and how queueing effects transaction flow. - [:custom-arrow: Explore rate limit options](/docs/build/transfers/native-token-transfers/configuration/rate-limiting/) + [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) - :octicons-unlock-16:{ .lg .middle } **Access Control** @@ -12979,12 +12979,12 @@ This section contains information on configuring Native Token Transfers (NTT), i Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. - [:custom-arrow: Explore access control roles](/docs/build/transfers/native-token-transfers/configuration/access-control/) + [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/rate-limiting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ --- BEGIN CONTENT --- --- title: Native Token Transfers Rate Limiting @@ -13083,7 +13083,7 @@ Queuing is configured dynamically during each transfer by passing the `shouldQue If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- title: Native Token Transfers EVM Deployment @@ -13273,7 +13273,7 @@ By default, NTT transfers to EVM blockchains support automatic relaying via the To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- title: Native Token Transfers Solana Deployment @@ -13383,7 +13383,7 @@ Deploying NTT with the CLI on Solana follows a structured process: Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -By default, NTT transfers to Solana require manual [relaying](/docs/learn/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. ## Set Up NTT @@ -13508,7 +13508,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -13529,7 +13529,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ --- BEGIN CONTENT --- --- title: Deploy Native Token Transfers with Launchpad @@ -13585,11 +13585,11 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Launch a Cross-Chain Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) 3. Set the token details: 1. Select the **home network** from the dropdown menu @@ -13598,22 +13598,22 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 4. Provide the **initial supply** 5. To the token details, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) 4. Select the deployment chains: 1. The home network where your token will be deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -13625,33 +13625,33 @@ Expand an existing token to support NTT across multiple chains. This process int 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Expand Your Existing Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) 3. Enter the token details: 1. Choose the home network where your token is already deployed (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) 4. Select the chains to deploy your token to: 1. The home network where your token is already deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 1. Click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -13661,7 +13661,7 @@ Expand an existing token to support NTT across multiple chains. This process int To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) The dashboard provides a high-level view of your token across all deployed chains, including: @@ -13669,7 +13669,7 @@ The dashboard provides a high-level view of your token across all deployed chain - Supply distribution visualization - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) ## Settings @@ -13684,16 +13684,16 @@ From this section, you can also: - **Pause the token** – temporarily turn off transfers on the selected chain - **Deploy to a new chain** – expand your token by deploying it to an additional chain -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) ### Role Management -This section displays key [roles](/docs/build/transfers/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - **Manager’s Owner** – the owner through the `NTTOwner` proxy - **Pauser** – the address authorized to pause transfers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) ### Security Threshold @@ -13704,7 +13704,7 @@ A higher transceiver threshold increases security by requiring more approvals be - **Registered Transceivers** – displays the number of registered transceivers and their addresses - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) ### Peer Chains Limits @@ -13715,7 +13715,7 @@ Define the transfer restrictions for each connected network. You can adjust: Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/ @@ -13748,7 +13748,7 @@ This section provides information on installing Wormhole's Native Token Transfer Find information on preparing for NTT deployment to EVM, including an example NTT token repository. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** @@ -13756,7 +13756,7 @@ This section provides information on installing Wormhole's Native Token Transfer Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. - [:custom-arrow: Deploy via Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/) + [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -13764,7 +13764,7 @@ This section provides information on installing Wormhole's Native Token Transfer Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy token and NTT contracts](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) - :octicons-search-16:{ .lg .middle } **Post Deployment** @@ -13780,7 +13780,7 @@ This section provides information on installing Wormhole's Native Token Transfer Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. - [:custom-arrow: Get help](/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/) + [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) --- END CONTENT --- @@ -13821,7 +13821,7 @@ Follow these steps to install the NTT CLI: ntt --version ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/){target=\_blank} to start using the CLI +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI ## Update NTT CLI @@ -13859,7 +13859,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to EVM chains](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/) + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - :octicons-tools-16:{ .lg .middle } **Deploy to Solana** @@ -13867,7 +13867,7 @@ Git branch and local installations enable a fast iteration loop as changes to th Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [:custom-arrow: Deploy NTT to Solana](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/) + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) --- END CONTENT --- @@ -13887,7 +13887,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} allows for a direct integration into your infrastructure +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -13922,7 +13922,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/troubleshooting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ --- BEGIN CONTENT --- --- title: Troubleshooting NTT Deployment @@ -13934,15 +13934,15 @@ categories: NTT, Transfer If you encounter issues during the NTT deployment process, check the following common points: -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#install-dependencies){target=\_blank} +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain - **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#configure-ntt){target=\_blank} + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} - **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file ???- interface "Dockerfile" @@ -14031,7 +14031,7 @@ If you encounter issues during the NTT deployment process, check the following c ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/faqs/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ --- BEGIN CONTENT --- --- title: Native Token Transfers FAQs @@ -14197,7 +14197,7 @@ The process for creating, deploying, and monitoring NTTs is as follows. Select t If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transfers/deployment-process/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. ## Additional Resources @@ -14209,7 +14209,7 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - [:custom-arrow: NTT CLI Commands](/docs/build/transfers/native-token-transfers/cli-commands/) + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - :octicons-question-16:{ .lg .middle } **NTT FAQs** @@ -14217,7 +14217,7 @@ Follow the [Deploy NTT with Launchpad](/docs/build/transfers/native-token-transf Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) --- END CONTENT --- @@ -14520,7 +14520,7 @@ Program log: Instruction: ReleaseInboundUnlock ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/faqs/ +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- title: Wormhole Settlement FAQs @@ -14567,7 +14567,7 @@ This section provides resources to build with Wormhole Settlement, including int Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. - [:custom-arrow: Build on the Liquidity layer](/docs/build/transfers/settlement/liquidity-layer/) + [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) - :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** @@ -14575,12 +14575,12 @@ This section provides resources to build with Wormhole Settlement, including int Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - [:custom-arrow: Run a Solver](/docs/build/transfers/settlement/solver/) + [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/liquidity-layer/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Liquidity Layer @@ -14691,7 +14691,7 @@ function placeMarketOrder( The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/solver/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ --- BEGIN CONTENT --- --- title: Wormhole Settlement Solver @@ -14935,7 +14935,7 @@ categories: Token-Bridge, Transfer ## Introduction -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. @@ -14943,8 +14943,8 @@ This page outlines the core contract methods needed to integrate Token Bridge fu To interact with the Wormhole Token Bridge, you'll need the following: -- [The address of the Token Bridge contract](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers ## How to Interact with Token Bridge Contracts @@ -15192,11 +15192,11 @@ This glossary is an index of technical term definitions for words commonly used Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} page. +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. ## Consistency Level -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page for details. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. ## Delivery Provider @@ -15212,7 +15212,7 @@ The finality of a transaction depends on its blockchain properties. Once a trans ## Guardian -A [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. ## Guardian Network @@ -15246,14 +15246,14 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi ## VAA -[Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. ## Validator A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/governance/architecture/ +Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ --- BEGIN CONTENT --- --- title: MultiGov Architecture @@ -15386,7 +15386,7 @@ This architecture ensures that MultiGov can operate securely and efficiently acr ![detailed multigov architecture diagram](/docs/images/learn/governance/multigov-detailed.webp) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/governance/faq/ +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ --- BEGIN CONTENT --- --- title: MultiGov Theoretical FAQs @@ -15446,7 +15446,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Discover MultiGov's hub-and-spoke architecture, enabling EVM and Solana cross-chain governance through coordinated decision-making. - [:custom-arrow: Learn about MultiGov architecture](/docs/learn/governance/architecture/) + [:custom-arrow: Learn about MultiGov architecture](/docs/products/multigov/concepts/architecture/) - :octicons-question-16:{ .lg .middle } **Theoretical FAQs** @@ -15454,7 +15454,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Find answers to common theoretical questions about MultiGov. - [:custom-arrow: Find the answer to your theoretical questions](/docs/learn/governance/faq/) + [:custom-arrow: Find the answer to your theoretical questions](/docs/products/multigov/faqs/) @@ -15476,7 +15476,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [:custom-arrow: Discover how to deploy MultiGov](/docs/build/multigov/deploy-to-evm/) + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** @@ -15484,7 +15484,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/build/multigov/deploy-to-solana/) + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - :octicons-code-square-16:{ .lg .middle } **Tutorials** @@ -15500,7 +15500,7 @@ Discover everything you need to know about MultiGov, Wormhole's cross-chain gove Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - [:custom-arrow: Find the answer to your technical questions](/docs/build/multigov/faq/) + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) --- END CONTENT --- @@ -15541,7 +15541,7 @@ MultiGov is important because it: The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/learn/governance/architecture/){target=\_blank} page. +For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. ![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/learn/governance/multigov-high-level.webp) @@ -15571,7 +15571,7 @@ To understand Wormhole from the ground up, visit the following sections. Learn more about the problems Wormhole solves, explore use cases, and view a list of supported blockchains. - [:custom-arrow: Introduction to Wormhole](/docs/learn/introduction/) + [:custom-arrow: Introduction to Wormhole](/docs/protocol/introduction/) - :octicons-book-16:{ .lg .middle } **Messaging Infrastructure** @@ -15579,7 +15579,7 @@ To understand Wormhole from the ground up, visit the following sections. Investigate the messaging protocol architecture with an in-depth exploration of the individual components powering Wormhole's infrastructure. - [:custom-arrow: Understand Wormhole's infrastructure](/docs/learn/infrastructure/) + [:custom-arrow: Understand Wormhole's infrastructure](/docs/protocol/infrastructure/) @@ -15683,7 +15683,7 @@ Explore MultiGov, Wormhole's multichain governance solution. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- title: Architecture @@ -15697,12 +15697,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -15714,17 +15714,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -15738,7 +15738,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -15751,7 +15751,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- title: Core Contracts @@ -15786,7 +15786,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -15794,13 +15794,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -15808,7 +15808,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -15822,7 +15822,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -15830,12 +15830,12 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- title: Guardians @@ -15853,7 +15853,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -15893,11 +15893,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -15926,7 +15926,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** @@ -15939,7 +15939,7 @@ These principles combine to create a clear pathway towards a fully trustless int --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ --- BEGIN CONTENT --- --- title: Infrastructure Components @@ -15963,7 +15963,7 @@ Start here for an overview of Wormhole architecture components and security mech Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - [:custom-arrow: Learn About Architecture](/docs/learn/infrastructure/architecture/) + [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - :octicons-book-16:{ .lg .middle } **Security** @@ -15971,7 +15971,7 @@ Start here for an overview of Wormhole architecture components and security mech Explore Wormhole's security features, including the Guardian network, governance, and monitoring. - [:custom-arrow: Learn About Security](/docs/learn/security/) + [:custom-arrow: Learn About Security](/docs/protocol/security/) @@ -15979,9 +15979,9 @@ Start here for an overview of Wormhole architecture components and security mech The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: -[timeline left(wormhole-docs/.snippets/text/learn/infrastructure/infrastructure-index-timeline.json)] +[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] -The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. ## Next Steps @@ -15993,7 +15993,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-people-16:{ .lg .middle } **Core Messaging Guides** @@ -16006,7 +16006,7 @@ The [Spy](/docs/learn/infrastructure/spy/) continuously runs in the background t --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- title: Relayers @@ -16018,7 +16018,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -16086,7 +16086,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -16152,7 +16152,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -16160,7 +16160,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -16168,12 +16168,12 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/spy/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ --- BEGIN CONTENT --- --- title: Spy @@ -16207,7 +16207,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -16259,7 +16259,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** @@ -16272,7 +16272,7 @@ A Spy can access the following categories of messages shared over the gossip pro --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- title: VAAs @@ -16284,7 +16284,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -16461,7 +16461,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -16473,7 +16473,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -16481,12 +16481,12 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/introduction/ --- BEGIN CONTENT --- --- title: Introduction to Wormhole @@ -16502,10 +16502,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -16527,7 +16527,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -16546,7 +16546,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos @@ -16642,7 +16642,7 @@ Wormhole supports a growing number of blockchains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/security/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- title: Security @@ -16654,7 +16654,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -16719,7 +16719,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits @@ -16774,13 +16774,13 @@ While this protocol is wholly separate from Wormhole itself, Wormhole builds on !!! note Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank} directly. +You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. ## Automatic Relaying To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/build/toolkit/typescript-sdk/){target=\_blank}. +This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. @@ -16879,7 +16879,7 @@ By leveraging a decentralized solver network, Settlement ensures efficient cross --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/architecture/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- title: Native Token Transfers Architecture @@ -16933,10 +16933,10 @@ How it works: 2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred 3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain -![NTT architecture diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-1.webp) +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) !!! note - [Learn more](/docs/learn/transfers/native-token-transfers/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. #### Custom Transceivers @@ -16944,7 +16944,7 @@ The NTT framework supports advanced features such as custom transceivers for spe NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -![Custom Attestation with NTT diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-2.webp) +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. @@ -17065,7 +17065,7 @@ This section covers Wormhole's Native Token Transfers (NTT), an open source, fle Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. - [:custom-arrow: Discover how NTT works](/docs/learn/transfers/native-token-transfers/architecture/) + [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) - :octicons-book-16:{ .lg .middle } **Deployment Models** @@ -17123,8 +17123,8 @@ categories: NTT, Transfer !!!tip "Looking to deploy NTT?" If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/){target=\_blank} + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} ## Introduction @@ -17171,12 +17171,12 @@ The Token Bridge offers a secure, low-effort integration suitable for applicatio - **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract - **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/learn/security/){target=\_blank} +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} - **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process - **Integration** - straightforward and permissionless method to deploy on multiple chains !!! note - [Learn more](/docs/learn/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. ## Supported Token Standards @@ -17215,7 +17215,7 @@ The registry component of the NTT system is crucial for maintaining a trusted li This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/architecture/ +Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ --- BEGIN CONTENT --- --- title: Settlement Protocol Architecture @@ -17239,7 +17239,7 @@ Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster- Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/learn/transfers/settlement/architecture/architecture-1.webp) +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. @@ -17281,7 +17281,7 @@ First, they lack a competitive price discovery mechanism as limit order prices a Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -![Mayan Swift - Intent-centric design](/docs/images/learn/transfers/settlement/architecture/architecture-2.webp) +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) ### Protocol Flow: How It Works @@ -17300,7 +17300,7 @@ Mayan Swift addresses these limitations by implementing competitive on-chain Eng Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -![Mayan MCTP diagram](/docs/images/learn/transfers/settlement/architecture/architecture-3.webp) +![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) ### Protocol Flow: How It Works @@ -17311,14 +17311,14 @@ Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} 3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/build/transfers/settlement/liquidity-layer/){target=\_blank} guide +- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- @@ -17352,7 +17352,7 @@ This section covers Wormhole Settlement, an intent-based solution enabling fast Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. - [:custom-arrow: Discover protocol architectures](/docs/learn/transfers/settlement/architecture/) + [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) --- END CONTENT --- @@ -17402,7 +17402,7 @@ Due to the hub-spoke model of liquidity, new chains without proven traction can ## Related Resources -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/learn/transfers/settlement/architecture/){target=\_blank} page +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page --- END CONTENT --- Doc-Content: https://wormhole.com/docs/learn/transfers/token-bridge/ @@ -17419,19 +17419,19 @@ Transferring tokens across blockchain networks is challenging due to the lack of Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. ### How Does It Work? -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/learn/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/learn/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. -While the [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/learn/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). ### Token Transfer Flow @@ -17468,7 +17468,7 @@ One of the key challenges in cross-chain token transfers is maintaining the corr The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. -The [Wormhole Guardian Network](/docs/learn/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. ### Portal Bridge @@ -17497,7 +17497,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - [:custom-arrow: Start building](/docs/tutorials/connect/react-dapp/) + [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) @@ -17516,7 +17516,7 @@ Wormhole Connect makes it simple to link your application to multiple blockchain --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/connect/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ --- BEGIN CONTENT --- --- title: Integrate Connect into a React DApp Tutorial @@ -17572,7 +17572,7 @@ npm install @wormhole-foundation/wormhole-connect ### Integrate Connect into the Application -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/build/transfers/connect/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: === "JavaScript" @@ -17650,26 +17650,26 @@ To transfer tokens from Sui to Fuji in the Wormhole Connect interface: 2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network 3. Enter the amount of SUI tokens you wish to transfer - ![](/docs/images/tutorials/connect/react-dapp/connect-1.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) 4. Choose to view other routes - ![](/docs/images/tutorials/connect/react-dapp/connect-2.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) 5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) !!! note It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - ![](/docs/images/tutorials/connect/react-dapp/connect-3.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) 6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - ![](/docs/images/tutorials/connect/react-dapp/connect-4.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) 7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - ![](/docs/images/tutorials/connect/react-dapp/connect-5.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. @@ -17677,11 +17677,11 @@ Once the transaction has been submitted, Wormhole Connect will display the progr After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -![](/docs/images/tutorials/connect/react-dapp/connect-6.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. -![](/docs/images/tutorials/connect/react-dapp/connect-7.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) ## Resources @@ -17791,12 +17791,12 @@ Multichain assets, often represented as wrapped tokens, enable seamless cross-ch Learn how to register your token on both a source and target chain, and create a wrapped version for seamless interoperability. - [:custom-arrow: Register your assets now](/docs/tutorials/multichain-assets/multichain-token/) + [:custom-arrow: Register your assets now](/docs/products/token-bridge/tutorials/multichain-token/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/multichain-assets/multichain-token/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ --- BEGIN CONTENT --- --- title: Create Multichain Tokens @@ -17829,7 +17829,7 @@ The first step in creating a multichain token is registering your token on its s 4. Locate the **Asset** field and paste the token contract address 5. Click **Next** to proceed -![Source Chain Registration Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-1.webp) +![Source Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp) ## Register the Token on the Target Chain @@ -17839,7 +17839,7 @@ After registering your token on the source chain, the next step is to select the 2. Connect your wallet to the target chain 3. Click **Next** to finalize the registration process -![Target Chain Registration Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-2.webp) +![Target Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp) ## Send an Attestation Attestation is a key step in the process. It verifies your token’s metadata, ensuring it is correctly recognized on the target chain’s blockchain explorer (e.g., [Etherscan](https://etherscan.io/){target=\_blank}). @@ -17847,7 +17847,7 @@ Attestation is a key step in the process. It verifies your token’s metadata, e 1. Click **Attest** to initiate the attestation process 2. Approve the transaction in your wallet when prompted -![Send Attestation Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-3.webp) +![Send Attestation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp) !!! note - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token @@ -17860,11 +17860,11 @@ The final step is to create the wrapped token on the target chain. This token re 1. Click **Create** to generate the wrapped token 2. Approve the transaction in your wallet when prompted -![Create Wrapped Token Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-4.webp) +![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: -![Confirmation Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-5.webp) +![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) ## Additional Steps and Recommendations @@ -17914,7 +17914,7 @@ Welcome to the MultiGov tutorials section. In this section, you will find tutori Learn how to propose governance actions on a hub chain, gather votes from spoke chains, aggregate the results, and carry out the final decision. Following these steps, you’ll master end-to-end governance workflows spanning multiple networks. - [:custom-arrow: Start building](/docs/tutorials/multigov/treasury-proposal/) + [:custom-arrow: Start building](/docs/products/multigov/tutorials/treasury-proposal/) @@ -17942,7 +17942,7 @@ Welcome to the MultiGov tutorials section. In this section, you will find tutori --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/multigov/treasury-proposal/ +Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ --- BEGIN CONTENT --- --- title: MultiGov Guides @@ -18220,7 +18220,7 @@ Before beginning this project, make sure you have the following: - **Data for parameters** - you will need: - - [Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} for the source and destination chains + - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - An contract address for the token you want to swap and the token you want to receive on the destination chain ## Configure and Setup @@ -18344,7 +18344,7 @@ performSwap(); ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/solidity-sdk/cross-chain-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ --- BEGIN CONTENT --- --- title: Create Cross-Chain Contracts @@ -18367,11 +18367,11 @@ This tutorial assumes a basic understanding of Solidity and smart contract devel ## Wormhole Overview -We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. +We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) ## Prerequisites @@ -18757,7 +18757,7 @@ Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the ``` !!! note - The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/build/reference/){target=\_blank}. + The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/){target=\_blank}. 2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction @@ -19268,7 +19268,7 @@ You're now fully equipped to build cross-chain contracts using the Wormhole prot - Monitor the status of your cross-chain transactions using the Wormhole Explorer and Wormhole-Solidity-SDK --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/solidity-sdk/cross-chain-token-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-token-contracts/ --- BEGIN CONTENT --- --- title: Cross-Chain Token Transfers @@ -19615,7 +19615,7 @@ contract CrossChainReceiver is TokenReceiver { - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface -After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/learn/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. +After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. ??? tip "Understanding the `TokenReceived` Struct" @@ -19733,7 +19733,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. - For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/build/reference/contract-addresses/){target=_blank}. + For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. !!! note You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. @@ -20899,7 +20899,7 @@ Expand the reach of your decentralized applications by building smart contracts Learn how to build and deploy smart contracts that communicate seamlessly across multiple blockchains. This tutorial walks you through using Wormhole's Solidity SDK to send and receive messages between Avalanche Fuji and Celo Alfajores, helping you master emitter validation, relayer usage, and cross-chain cost management. - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-contracts/) + [:custom-arrow: Start building](/docs/products/messaging/tutorials/cross-chain-contracts/) - :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Token Transfer Contracts** @@ -20907,7 +20907,7 @@ Expand the reach of your decentralized applications by building smart contracts Discover how to create a fully functional cross-chain token transfer system using Wormhole's Solidity SDK. This tutorial guides you through token attestation, contract deployment, and secure transfers of ERC-20 tokens between test networks. By the end, you’ll know how to tap into global liquidity and enrich your dApps with seamless multi-chain asset movement. - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) + [:custom-arrow: Start building](/docs/products/messaging/tutorials/cross-chain-token-contracts/) @@ -20921,7 +20921,7 @@ Expand the reach of your decentralized applications by building smart contracts Dive deeper into Wormhole’s foundational concepts for cross-chain contracts. Discover how messaging, guardians, and VAAs work together to enable secure, scalable dApps. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) --- END CONTENT --- @@ -20947,7 +20947,7 @@ The Wormhole SDK provides the essential building blocks for creating robust cros Learn how to move native USDC across chains using Circle’s CCTP and Wormhole’s TypeScript SDK. This tutorial shows you how to streamline transfers with automated attestation and finalization or take complete control with manual steps. Gain the skills to handle seamless USDC bridging, optimize user experience, and improve the reliability of your cross-chain applications. - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/usdc-via-cctp/) + [:custom-arrow: Start building](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/) - :octicons-repo-16:{ .lg .middle } **Transfer Tokens via the Token Bridge** @@ -20955,7 +20955,7 @@ The Wormhole SDK provides the essential building blocks for creating robust cros Learn how to build a versatile cross-chain token transfer application using Wormhole’s TypeScript SDK. This tutorial walks you through leveraging the Token Bridge to securely and efficiently move assets between EVM and non-EVM chains. By the end, you’ll understand how to transfer tokens between networks like Ethereum, Solana, Sui, and beyond, opening the door to an interconnected blockchain ecosystem. - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/) + [:custom-arrow: Start building](/docs/products/token-bridge/tutorials/transfer-workflow/) @@ -20969,12 +20969,12 @@ The Wormhole SDK provides the essential building blocks for creating robust cros Learn to build cross-chain dApps using the Wormhole SDK. Access detailed guides, reference code, and best practices for robust application development. - [:custom-arrow: Learn more](/docs/build/toolkit/typescript-sdk/) + [:custom-arrow: Learn more](/docs/tools/typescript-sdk/get-started/) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/tokens-via-token-bridge/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/transfer-workflow/ --- BEGIN CONTENT --- --- title: Transfer Tokens via Token Bridge Tutorial @@ -21221,7 +21221,7 @@ import { getSigner } from '../helpers/helpers'; } ``` - If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/#token-transfers). Otherwise, an attestation must be generated. + If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. 7. **Set up the source chain signer** - the signer creates and submits the attestation transaction @@ -21785,7 +21785,7 @@ You've successfully built a cross-chain token transfer application using Wormhol The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/usdc-via-cctp/ +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ --- BEGIN CONTENT --- --- title: Transfer USDC via CCTP and Wormhole SDK @@ -22321,7 +22321,7 @@ Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain Learn how to fetch VAAs, verify their validity, and replace outdated signatures using the Wormholescan API and Wormhole SDK. - [:custom-arrow: Start tutorial](/docs/tutorials/wormholescan/replace-signatures/) + [:custom-arrow: Start tutorial](/docs/products/messaging/tutorials/replace-signatures/) @@ -22340,7 +22340,7 @@ Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/replace-signatures/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ --- BEGIN CONTENT --- --- title: Replace Outdated Signatures in VAAs @@ -22353,7 +22353,7 @@ description: Learn how to fetch, validate, and replace outdated signatures in Wo ## Introduction -Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. +Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. @@ -22457,12 +22457,12 @@ export const TXS = [ ``` - **`RPC`** - endpoint for interacting with an Ethereum RPC node - - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs + - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts - **`TXS`** - list of example transaction hashes that will be used for testing -7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs +7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs ```typescript title="src/config/layouts.ts" export const PARSE_AND_VERIFY_VM_ABI = { @@ -22537,7 +22537,7 @@ The VAA ID is structured as follows: chain/emitter/sequence ``` - - `chain` - the [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} (Ethereum is 2) + - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) - `emitter` - the contract address that emitted the VAA - `sequence` - a unique identifier for the event diff --git a/llms.txt b/llms.txt index 291ad9eac..011e0e552 100644 --- a/llms.txt +++ b/llms.txt @@ -4,116 +4,116 @@ ## Docs -- [Get Started with Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/core-contracts.md): This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +- [Get Started with Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md): This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts - [Core Messaging Layer Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/index.md): Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. -- [Wormhole-Deployed Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/wormhole-relayers.md): Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +- [Wormhole-Deployed Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md): Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [Build with Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/index.md): Learn how to start building multichain solutions on Wormhole, with tips to get started, an overview of the toolkit, and an introduction to the protocols. - [Run Infrastructure Services](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/index.md): Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. - [Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/index.md): Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. - [Run a Relayer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md): Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/index.md): Discover everything you need to about the Wormhole Spy, a daemon that watches the Guardian Network and subscribe to signed messages. -- [Run a Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/run-spy.md): Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. -- [Deploy MultiGov on EVM Chains](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-evm.md): Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. -- [MultiGov Deployment to Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/deploy-to-solana.md): Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. -- [MultiGov Technical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/faq.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +- [Run a Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md): Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. +- [Deploy MultiGov on EVM Chains](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md): Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +- [MultiGov Deployment to Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md): Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. +- [MultiGov Technical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. - [Getting Started with MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/index.md): Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -- [Upgrading MultiGov on EVM](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-evm.md): Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. -- [Upgrading MultiGov on Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/upgrade-solana.md): Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. -- [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. +- [Upgrading MultiGov on EVM](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md): Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. +- [Upgrading MultiGov on Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md): Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. +- [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. - [Wormhole Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/index.md): Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. - [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md): Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. - [Use Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md): Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -- [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. -- [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. -- [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. -- [Reference](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/index.md): Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -- [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +- [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. +- [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. +- [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. +- [Reference](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/index.md): Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. +- [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. - [Start Building](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/index.md): This section has all you need to start developing with Wormhole, including a guide to supported networks, tool sets, and code examples. - [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/supported-networks.md): Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. -- [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. +- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +- [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. - [Use Cases](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md): Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - [Wormhole CLI](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md): Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. - [Local Dev Environment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md): Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. - [Toolkit FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md): FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. - [Wormhole Tooling](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/index.md): This page lists key dev tools, including the WormholeScan Explorer, Wormhole CLI, Wormhole SDKs, and APIs for querying network data. -- [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/solidity-sdk.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. +- [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. - [Wormhole SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/index.md): The Wormhole SDK provides tools for cross-chain communication, token bridges, and more, enabling developers to integrate with multiple blockchain environments. -- [Building Protocols and Payloads](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/protocols-payloads.md): Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. -- [Data Layouts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/sdk-layout.md): Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. -- [VAAs and Protocols](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/vaas-protocols.md): Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. -- [Wormhole TS SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/wormhole-sdk.md): Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. +- [Building Protocols and Payloads](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md): Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. +- [Data Layouts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md): Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. +- [VAAs and Protocols](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md): Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. +- [Wormhole TS SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md): Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. - [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -- [Configure Your Connect Widget v0](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration-v0.md): Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. -- [Connect Data Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-data.md): Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. -- [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/configure-theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. +- [Configure Your Connect Widget v0](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md): Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. +- [Connect Data Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md): Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +- [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. - [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. -- [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -- [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/features.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. +- [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +- [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. - [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. - [Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md): Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -- [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -- [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. +- [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +- [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. - [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/index.md): This section guides you through using Wormhole products to securely and efficiently transfer assets and messages across multiple blockchains. -- [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -- [Native Token Transfers Access Control](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/access-control.md): Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +- [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +- [Native Token Transfers Access Control](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md): Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. - [Native Token Transfers (NTT) - Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/index.md): This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -- [Native Token Transfers Rate Limiting](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/rate-limiting.md): Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. -- [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -- [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -- [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +- [Native Token Transfers Rate Limiting](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md): Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. +- [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +- [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +- [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. - [Native Token Transfers (NTT) - Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/index.md): This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. - [Native Token Transfers Installation](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md): Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. - [Native Token Transfers Post Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md): Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -- [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/troubleshooting.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. -- [Native Token Transfers FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/faqs.md): Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +- [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +- [Native Token Transfers FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md): Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [Native Token Transfers (NTT)](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/index.md): This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. - [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -- [Wormhole Settlement FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/faqs.md): Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. +- [Wormhole Settlement FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md): Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. - [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/index.md): Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. -- [Wormhole Settlement Liquidity Layer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/liquidity-layer.md): Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -- [Wormhole Settlement Solver](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/solver.md): Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +- [Wormhole Settlement Liquidity Layer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md): Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. +- [Wormhole Settlement Solver](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md): Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md): Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. - [Glossary](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md): Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -- [MultiGov Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/architecture.md): Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. -- [MultiGov Theoretical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/faq.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +- [MultiGov Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md): Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. +- [MultiGov Theoretical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. - [Learn about MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/index.md): Explore the MultiGov documentation for a comprehensive guide covering architecture, deployment, upgrading, integration, and FAQs. - [MultiGov Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md): Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. - [Learn about Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/index.md): Learn the basics of Wormhole, covering its architecture, messaging protocols, and how it enables multichain communication and asset transfers. -- [Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/architecture.md): Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -- [Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/core-contracts.md): Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -- [Guardians](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/guardians.md): Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -- [Infrastructure Components](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/index.md): Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -- [Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/relayer.md): Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -- [Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/spy.md): Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -- [VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/infrastructure/vaas.md): Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -- [Introduction to Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/introduction.md): Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -- [Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/security.md): Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +- [Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md): Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +- [Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md): Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. +- [Guardians](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md): Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +- [Infrastructure Components](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/index.md): Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. +- [Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md): Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +- [Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md): Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +- [VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md): Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +- [Introduction to Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md): Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +- [Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md): Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. - [Circle's CCTP Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md): Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. - [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/index.md): This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -- [Native Token Transfers Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/architecture.md): Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +- [Native Token Transfers Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md): Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. - [Native Token Transfers - Deployment Models](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md): Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. - [A Quick Look at Native Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/index.md): This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. - [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md): Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. - [Native Token Transfers Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md): Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -- [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. +- [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. - [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/index.md): Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. - [Wormhole Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md): Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. - [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. - [Wormhole Connect Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/index.md): Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -- [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +- [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. - [Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/index.md): Discover product-specific Wormhole tutorials. Learn setup, integration, and advanced features to develop cross-chain apps confidently. - [Multichain Assets Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/index.md): Explore comprehensive, step-by-step tutorials on how to register, manage, and work with multichain assets within the Wormhole ecosystem. -- [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. +- [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. - [Step-by-Step MultiGov Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/index.md): Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. -- [MultiGov Guides](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/treasury-proposal.md): Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. +- [MultiGov Guides](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md): Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. - [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.index.md): Follow step-by-step tutorials to integrate Wormhole Settlement Routes using the SDK for seamless cross-chain swaps and efficient asset transfers. - [Wormhole Settlements](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.settlement-routes.md): Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. -- [Create Cross-Chain Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/cross-chain-contracts.md): Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. -- [Cross-Chain Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/cross-chain-token-contracts.md): Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. +- [Create Cross-Chain Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md): Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. +- [Cross-Chain Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md): Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. - [Solidity SDK Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/index.md): Master cross-chain smart contracts with Wormhole's Solidity SDK. Learn messaging, token transfers, and secure, scalable dApp deployments across blockchains. - [Wormhole SDK Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/index.md): Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. -- [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/tokens-via-token-bridge.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [Transfer USDC via CCTP and Wormhole SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/usdc-via-cctp.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +- [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [Transfer USDC via CCTP and Wormhole SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. - [Wormholescan API Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/index.md): Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. -- [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. \ No newline at end of file +- [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. \ No newline at end of file diff --git a/ntt/.pages b/ntt/.pages deleted file mode 100644 index 5edcebdb5..000000000 --- a/ntt/.pages +++ /dev/null @@ -1,3 +0,0 @@ -nav: - - index.md - - overview.md diff --git a/ntt/architecture.md b/ntt/architecture.md deleted file mode 100644 index b92f19b34..000000000 --- a/ntt/architecture.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Native Token Transfers Architecture -description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. -categories: NTT, Transfer ---- - -## Native Token Transfers Architecture - -The Native Token Transfers (NTT) architecture enables secure and efficient native token transfers across blockchains. Designed for flexibility and composability, it coordinates minting, burning, and message verification through a set of on-chain contracts and cross-chain messaging. - -This page outlines the core components, how they interact, and the underlying mechanisms that ensure consistent token behavior across supported chains. - -## High-level Overview - -There are a few core components involved in NTTs: - -- NTT Manager - integrator owned contract on source chain -- Wormhole Transceiver on source chain- -- Wormhole Core Contract on source chain - -- Guardian Network -- Relayer -- Wormhole Transceiver on destination chain -- Wormhole core contract on destination chain -- NTT manager - integrator owned contract on destination chain diff --git a/ntt/overview.md b/ntt/overview.md deleted file mode 100644 index 1712b7779..000000000 --- a/ntt/overview.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- - -# Native Token Transfers - -Native Token Transfers (NTT) is an open-source and composable framework for moving tokens between blockchains without relying on wrapped assets. It enables developers and protocol teams to maintain native token behavior, supply control, and unified token economics across chains. - -Unlike traditional bridges that use wrapped assets—leading to fragmented liquidity and governance complexity—NTT uses canonical token deployments and a single mint-and-burn model to keep total supply in sync. - -## Key Features - -- [x] **No wrapped assets** – tokens retain their native format on each chain -- [x] **Canonical deployments** – one unified token identity across chain -- [x] **Supply control** – enforced mint-and-burn model maintains global supply integrity -- [x] **Composable** – open-source and extensible for widespread adoption and integration with other protocols -- [x] **Customizable controls** – configure rate limits, access control, and attestation thresholds - -## Use Cases - -Generally speaking, NTT can be used by developers building multichain dApps, token issuers creating and deploying a single token across multiple chains, and governance platforms utilizing native tokens for cross-chain voting and decision-making. Below are some specific use cases where NTT provides added value: - -??? interface "Cross-chain swaps and liquidity aggregation" - - 💡 Enable seamless swaps between chains with real-time liquidity routing. - - 🛠 **Wormhole products used:** - - - [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - - 🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators - - 🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -??? interface "Borrowing and lending" - - 💡 Let users borrow assets on one chain using collateral from another. - - 🛠 **Wormhole products used:** - - - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - - 🔗 **Used in:** Lending protocols and yield platforms - - 🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -??? interface "Asset movement between Bitcoin and other chains" - - 💡 Enable direct BTC transfers without wrapped assets. - - 🛠 **Wormhole products used:** - - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains - - 🔗 **Used in:** Bitcoin DeFi and lightning network integrations - - 🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -??? interface "Memecoin launchpads" - - 💡 Launch and distribute memecoins across multiple chains, enabling cross-chain fund raising and liquidity access. - - 🛠 **Wormhole products used:** - - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising - - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - - 🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -??? interface "Gas abstraction" - - 💡 Allow users to pay gas fees with any token across different networks, removing fric tion in multichain interactions. - - 🛠 **Wormhole products used:** - - - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – routes gas fee payments across chains - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments - - 🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -??? interface "Cross-chain payment widgets" - - 💡 Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - - 🛠 **Wormhole products used:** - - - [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers - - 🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -??? interface "Cross-chain staking" - - 💡 Enable users to stake assets on one chain while earning rewards or securing networks on another. - - 🛠 **Wormhole products used:** - - - [**Messaging**](/docs/learn/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains - - [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks - - 🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks - - 🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -## Integration Process - -The process for creating, deploying, and monitoring NTTs is as follows. - -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] - -## Deployment Models - -NTT offers two deployment models, each catering to different token management needs: - -- **Hub-and-spoke** - - Locks tokens on a central hub chain and mints equivalent tokens on destination spoke chains, preserving the canonical balance and enabling secure cross-chain transfers. - - Most suitable for existing token deployments that don't want to alter existing token contracts - -- **Burn-and-mint** - - Burns tokens on the source chain and mints equivalent tokens on the destination chain, creating a native multichain token and simplifying the transfer process. - - Most suitable for new token deployments or projects willing to upgrade existing contracts - -## Next Steps - -
- -- :octicons-tools-16:{ .lg .middle } **Start building** - - --- - - Follow these steps to begin the integration process and deploy NTT. - - [:custom-arrow: Get started]() - -- :octicons-tools-16:{ .lg .middle } **Learn how NTT works** - - --- - - Discover NTT's architecture and how it enables cross-chain token transfers. - - [:custom-arrow: Explore architecture]() - -
\ No newline at end of file diff --git a/products/.pages b/products/.pages new file mode 100644 index 000000000..7a3d070ff --- /dev/null +++ b/products/.pages @@ -0,0 +1,11 @@ +nav: + - 'Product Overview': products.md + - connect + - native-token-transfers + - settlement + - token-bridge + - cctp-bridge + - multigov + - queries + - messaging + - reference diff --git a/products/cctp-bridge/.pages b/products/cctp-bridge/.pages new file mode 100644 index 000000000..d59ff1898 --- /dev/null +++ b/products/cctp-bridge/.pages @@ -0,0 +1,7 @@ +title: CCTP Bridge +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- tutorials +- concepts diff --git a/products/cctp-bridge/concepts/.pages b/products/cctp-bridge/concepts/.pages new file mode 100644 index 000000000..492548c78 --- /dev/null +++ b/products/cctp-bridge/concepts/.pages @@ -0,0 +1,4 @@ +title: Concepts +nav: +- 'Wormhole Integration': integration.md +- 'CCTP Docs': https://developers.circle.com/stablecoins/cctp-getting-started diff --git a/products/cctp-bridge/concepts/integration.md b/products/cctp-bridge/concepts/integration.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/cctp-bridge/concepts/integration.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/cctp-bridge/get-started.md b/products/cctp-bridge/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/cctp-bridge/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/cctp-bridge/guides/.pages b/products/cctp-bridge/guides/.pages new file mode 100644 index 000000000..1930ddb9f --- /dev/null +++ b/products/cctp-bridge/guides/.pages @@ -0,0 +1,3 @@ +title: Guides +nav: +- 'Transfer USDC': transfer-usdc.md diff --git a/products/cctp-bridge/guides/transfer-usdc.md b/products/cctp-bridge/guides/transfer-usdc.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/cctp-bridge/guides/transfer-usdc.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/cctp-bridge/overview.md b/products/cctp-bridge/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/cctp-bridge/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/cctp-bridge/tutorials/.pages b/products/cctp-bridge/tutorials/.pages new file mode 100644 index 000000000..dfdff76e5 --- /dev/null +++ b/products/cctp-bridge/tutorials/.pages @@ -0,0 +1,3 @@ +title: Tutorials +nav: +- 'Complete USDC Transfer Flow': complete-usdc-transfer.md diff --git a/tutorials/typescript-sdk/usdc-via-cctp.md b/products/cctp-bridge/tutorials/complete-usdc-transfer.md similarity index 89% rename from tutorials/typescript-sdk/usdc-via-cctp.md rename to products/cctp-bridge/tutorials/complete-usdc-transfer.md index ec15eb126..84b0968a4 100644 --- a/tutorials/typescript-sdk/usdc-via-cctp.md +++ b/products/cctp-bridge/tutorials/complete-usdc-transfer.md @@ -1,9 +1,9 @@ --- -title: Transfer USDC via CCTP and Wormhole SDK +title: Complete USDC Transfer Flow description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. --- -# Transfer USDC via CCTP and Wormhole SDK +# Complete USDC Transfer Flow :simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} @@ -84,7 +84,7 @@ In this section, you'll set up your project for transferring USDC across chains 2. Open the `helpers.ts` file and add the following code ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-1.ts" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-1.ts" ``` - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file @@ -101,7 +101,7 @@ In this section, you'll set up your project for transferring USDC across chains 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:1:4" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:1:4" ``` - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more @@ -123,7 +123,7 @@ Before initiating a cross-chain transfer, you must set up the chain context and 1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:6:7" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:6:7" ``` !!! note @@ -132,25 +132,25 @@ Before initiating a cross-chain transfer, you must set up the chain context and 2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:10:11" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:10:11" ``` 3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:14:15" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:14:15" ``` 4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:18:18" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:18:18" ``` 5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:20:20" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:20:20" ``` #### Initiate the Transfer @@ -160,13 +160,13 @@ To begin the manual transfer process, you first need to create the transfer obje 1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:23:28" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:23:28" ``` 2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:34:35" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:34:35" ``` #### Fetch the Circle Attestation (VAA) @@ -177,13 +177,13 @@ Once you initialize the transfer on the source chain, you must fetch the VAA fro 1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:38:38" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:38:38" ``` 2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:40:41" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:40:41" ``` The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain @@ -195,7 +195,7 @@ Once you fetch the VAA correctly, the final step is to complete the transfer on Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain ```typescript ---8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts:45:50" +--8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts:45:50" ``` The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed @@ -204,7 +204,7 @@ You can find the full code for the manual USDC transfer script below: ???- code "`manual-transfer.ts`" ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-2.ts" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-2.ts" ``` ### Run Manual Transfer @@ -228,7 +228,7 @@ This feature is handy for recovering an incomplete transfer or when debugging. Here’s how you can complete a partial transfer using just the source chain and transaction hash: ```typescript ---8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-4.ts:19:29" +--8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-4.ts:19:29" ``` You will need to provide the below requirements to complete the partial transfer: @@ -242,7 +242,7 @@ You can find the full code for the manual USDC transfer script below: ??? code "`partial-transfer.ts`" ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-4.ts" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-4.ts" ``` ## Automatic Transfers @@ -256,7 +256,7 @@ The automatic transfer process simplifies the steps by automating the attestatio The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you ```typescript ---8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts:21:21" +--8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts:21:21" ``` #### Initiate the Transfer @@ -264,7 +264,7 @@ The setup for automatic transfers is similar to manual transfers, with the key d The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain ```typescript ---8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts:24:29" +--8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts:24:29" ``` #### Log Transfer Details @@ -272,14 +272,14 @@ The transfer process is the same as that for manual transfers. You create the tr After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer ```typescript ---8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts:35:38" +--8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts:35:38" ``` You can find the full code for the automatic USDC transfer script below: ??? code "`automatic-transfer.ts`" ```typescript - --8<-- "code/tutorials/typescript-sdk/usdc-via-cctp/cctp-sdk-3.ts" + --8<-- "code/products/cctp-bridge/tutorials/complete-usdc-transfer/cctp-sdk-3.ts" ``` ### Run Automatic Transfer diff --git a/products/connect/.pages b/products/connect/.pages new file mode 100644 index 000000000..931e1c845 --- /dev/null +++ b/products/connect/.pages @@ -0,0 +1,10 @@ +title: Connect +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- configuration +- guides +- tutorials +- concepts +- 'FAQs': faqs.md +- reference \ No newline at end of file diff --git a/products/connect/concepts/.pages b/products/connect/concepts/.pages new file mode 100644 index 000000000..fc2b4576c --- /dev/null +++ b/products/connect/concepts/.pages @@ -0,0 +1,3 @@ +title: Concepts +nav: +- 'Routes': routes.md \ No newline at end of file diff --git a/build/transfers/connect/routes.md b/products/connect/concepts/routes.md similarity index 91% rename from build/transfers/connect/routes.md rename to products/connect/concepts/routes.md index 02e8b64a0..ef3139d16 100644 --- a/build/transfers/connect/routes.md +++ b/products/connect/concepts/routes.md @@ -6,11 +6,11 @@ categories: Connect, Transfer ## Routes Overview {: #routes-overview} -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/build/transfers/connect/configuration/){target=\_blank}. +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/build/transfers/connect/features/){target=\_blank} to see under which exact conditions the routes appear. +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. ## Token Bridge Routes {: #token-bridge-routes} @@ -40,7 +40,7 @@ Trustless relayers can execute the second transaction on the user's behalf. Ther ## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/build/transfers/connect/configuration/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. #### Manual Route {: #manual-route-ntt} diff --git a/products/connect/configuration/.pages b/products/connect/configuration/.pages new file mode 100644 index 000000000..d0fb8bdcd --- /dev/null +++ b/products/connect/configuration/.pages @@ -0,0 +1,4 @@ +title: Configuration +nav: +- 'Data': data.md +- 'Theme': theme.md \ No newline at end of file diff --git a/build/transfers/connect/configuration-v0.md b/products/connect/configuration/configuration-v0.md similarity index 93% rename from build/transfers/connect/configuration-v0.md rename to products/connect/configuration/configuration-v0.md index fbf5bac95..01252978c 100644 --- a/build/transfers/connect/configuration-v0.md +++ b/products/connect/configuration/configuration-v0.md @@ -12,7 +12,7 @@ Wormhole Connect is a flexible React widget that streamlines cross-chain asset t This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. !!! note - For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/build/transfers/connect/configuration/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/build/transfers/connect/upgrade/){target=\_blank} for detailed instructions. + For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/products/connect/configuration/data/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. ## Get Started @@ -21,13 +21,13 @@ Configure the Wormhole Connect React component by passing a `WormholeConnectConf === "React" ```ts - --8<-- 'code/build/transfers/connect/configuration/configure-react-v0.tsx' + --8<-- 'code/products/connect/configuration/configuration-v0/configure-react-v0.tsx' ``` === "HTML Tags" ```html - --8<-- 'code/build/transfers/connect/configuration/configure-html.html' + --8<-- 'code/products/connect/configuration/configuration-v0/configure-html.html' ``` ## Examples {: #examples } @@ -36,7 +36,7 @@ Below are some examples of different ways you can configure Connect. See `Wormho ??? code "View `WormholeConnectConfig`" ```ts - --8<-- 'code/build/transfers/connect/configuration/index.ts' + --8<-- 'code/products/connect/configuration/configuration-v0/index.ts' ``` ### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints } @@ -46,13 +46,13 @@ Specify supported networks, tokens, and custom RPC endpoints. Your users may enc === "Mainnet" ```js - --8<-- 'code/build/transfers/connect/configuration/custom-simple-v0.jsx' + --8<-- 'code/products/connect/configuration/configuration-v0/custom-simple-v0.jsx' ``` === "Testnet" ```js - --8<-- 'code/build/transfers/connect/configuration/custom-simple-testnet-v0.tsx' + --8<-- 'code/products/connect/configuration/configuration-v0/custom-simple-testnet-v0.tsx' ``` !!! note @@ -63,7 +63,7 @@ Specify supported networks, tokens, and custom RPC endpoints. Your users may enc Wormhole Connect offers a high level of customizability that suits and integrates with your application's design, including various options for buttons, backgrounds, popovers, fonts, and more. The following example demonstrates a variety of appearance customizations. Remember, if you prefer a visual to aid in designing your widget, you can use the [no code style interface](https://connect-in-style.wormhole.com/){target=\_blank}. ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-full.jsx' +--8<-- 'code/products/connect/configuration/configuration-v0/custom-full.jsx' ``` ### Environment {: #environment } @@ -109,7 +109,7 @@ This example configuration limits Connect to the Solana and Ethereum networks an See [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. ```json ---8<-- 'code/build/transfers/connect/configuration/arbitrary-token.tsx' +--8<-- 'code/products/connect/configuration/configuration-v0/arbitrary-token.tsx' ``` ## More Configuration Options {: #more-configuration-options } @@ -214,7 +214,7 @@ By setting the `showHamburgerMenu` option to `false,` you can add extra links. T #### Sample Configuration {: #sample-configuration } ```json ---8<-- 'code/build/transfers/connect/configuration/sample-configuration.json' +--8<-- 'code/products/connect/configuration/configuration-v0/sample-configuration.json' ``` ### CoinGecko API Key {: #coingecko-api-key } @@ -240,7 +240,7 @@ Specify a set of extra networks to be displayed on the network selection modal, ??? code "View full configuration" ```json - --8<-- 'code/build/transfers/connect/configuration/advanced-configuration.json' + --8<-- 'code/products/connect/configuration/configuration-v0/advanced-configuration.json' ``` ### More Tokens {: #more-tokens } diff --git a/build/transfers/connect/configuration/configure-data.md b/products/connect/configuration/data.md similarity index 89% rename from build/transfers/connect/configuration/configure-data.md rename to products/connect/configuration/data.md index a69b739a5..a66deb8e9 100644 --- a/build/transfers/connect/configuration/configure-data.md +++ b/products/connect/configuration/data.md @@ -15,13 +15,13 @@ Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `c === "React integration" ```ts - --8<-- 'code/build/transfers/connect/configuration/configure-react-v1.tsx' + --8<-- 'code/products/connect/configuration/data/configure-react-v1.tsx' ``` === "Hosted integration" ```ts - --8<-- 'code/build/transfers/connect/configuration/configure-hosted.tsx' + --8<-- 'code/products/connect/configuration/data/configure-hosted.tsx' ``` !!! note @@ -36,13 +36,13 @@ Connect lets you customize the available chains to match your project's needs. Y === "Mainnet" ```js - --8<-- 'code/build/transfers/connect/configuration/custom-simple-v1.jsx' + --8<-- 'code/products/connect/configuration/data/custom-simple-v1.jsx' ``` === "Testnet" ```js - --8<-- 'code/build/transfers/connect/configuration/custom-simple-testnet-v1.jsx' + --8<-- 'code/products/connect/configuration/data/custom-simple-testnet-v1.jsx' ``` !!! note @@ -78,15 +78,15 @@ For further details on the `route` plugin interface, refer to the [Wormhole Type To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: ```typescript ---8<-- 'code/build/transfers/connect/configuration/example-cctp.ts' +--8<-- 'code/products/connect/configuration/data/example-cctp.ts' ``` #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript ---8<-- 'code/build/transfers/connect/configuration/example-all-routes.ts' +--8<-- 'code/products/connect/configuration/data/example-all-routes.ts' ``` This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. @@ -103,7 +103,7 @@ This example configuration adds the BONK token to Connect. Note the `wrappedToke See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. ```typescript ---8<-- 'code/build/transfers/connect/configuration/add-token.tsx' +--8<-- 'code/products/connect/configuration/data/add-token.tsx' ``` ### Whitelisting Tokens {: #whitelisting-tokens } @@ -116,13 +116,13 @@ Connect offers a list of built-in tokens by default. You can see it below: You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-tokens-whitelist.jsx' +--8<-- 'code/products/connect/configuration/data/custom-tokens-whitelist.jsx' ``` You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-tokens-whitelist-advanced.jsx' +--8<-- 'code/products/connect/configuration/data/custom-tokens-whitelist-advanced.jsx' ``` ### User-Inputted Tokens {: #user-inputted-tokens } @@ -132,7 +132,7 @@ As of version 2.0, Connect allows users to paste token addresses to bridge any t If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-disable-arbitrary-tokens.jsx' +--8<-- 'code/products/connect/configuration/data/custom-disable-arbitrary-tokens.jsx' ``` Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. @@ -142,7 +142,7 @@ Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to pas Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-tx-settings-solana.jsx' +--8<-- 'code/products/connect/configuration/data/custom-tx-settings-solana.jsx' ``` !!! note @@ -164,5 +164,5 @@ If you would like to offer Reown Cloud (formerly WalletConnect) as a supported w The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-coingecko-key.jsx' +--8<-- 'code/products/connect/configuration/data/custom-coingecko-key.jsx' ``` diff --git a/build/transfers/connect/configuration/configure-theme.md b/products/connect/configuration/theme.md similarity index 93% rename from build/transfers/connect/configuration/configure-theme.md rename to products/connect/configuration/theme.md index a513f6c73..e4b54c438 100644 --- a/build/transfers/connect/configuration/configure-theme.md +++ b/products/connect/configuration/theme.md @@ -15,13 +15,13 @@ You can customize Connect's color scheme by providing a `theme` prop. === "React integration" ```ts - --8<-- 'code/build/transfers/connect/configuration/custom-colors.tsx' + --8<-- 'code/products/connect/configuration/theme/custom-colors.tsx' ``` === "Hosted integration" ```ts - --8<-- 'code/build/transfers/connect/configuration/custom-colors-hosted.tsx' + --8<-- 'code/products/connect/configuration/theme/custom-colors-hosted.tsx' ``` The `WormholeConnectTheme` type supports the following properties: @@ -54,5 +54,5 @@ By setting the `showHamburgerMenu` option to `false,` you can add extra links. T | `order` | Order where the new item should be injected | ```jsx ---8<-- 'code/build/transfers/connect/configuration/custom-menu.jsx' +--8<-- 'code/products/connect/configuration/theme/custom-menu.jsx' ``` diff --git a/build/transfers/connect/faqs.md b/products/connect/faqs.md similarity index 92% rename from build/transfers/connect/faqs.md rename to products/connect/faqs.md index f7eb7ff28..d4c9a4cfa 100644 --- a/build/transfers/connect/faqs.md +++ b/products/connect/faqs.md @@ -8,7 +8,7 @@ categories: Connect, Transfer ## What types of assets does Connect support? -Wormhole Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: +Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: - Major stablecoins like USDT and USDC (via CCTP) - Native gas tokens such as ETH, SOL, etc. @@ -24,7 +24,7 @@ Connect supports around 30 chains, spanning various blockchain runtimes: - Solana - Move-based chains (Sui, Aptos) -For a complete list of supported chains, see the [Connect-supported chains list](/docs/build/transfers/connect/features/){target=\_blank}. +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. ## What is gas dropoff? @@ -38,9 +38,9 @@ Connect can be [fully customized](https://connect-in-style.wormhole.com/){target Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. -## Do integrators need to enable wallets like Phantom or Backpack in Wormhole Connect? +## Do integrators need to enable wallets like Phantom or Backpack in Connect? -Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Wormhole Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. +Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. ## Which function should be modified to set priority fees for Solana transactions? diff --git a/products/connect/get-started.md b/products/connect/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/connect/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/connect/guides/.pages b/products/connect/guides/.pages new file mode 100644 index 000000000..4c071d7b7 --- /dev/null +++ b/products/connect/guides/.pages @@ -0,0 +1,3 @@ +title: Guides +nav: +- 'Migration to v1': upgrade.md \ No newline at end of file diff --git a/build/transfers/connect/upgrade.md b/products/connect/guides/upgrade.md similarity index 98% rename from build/transfers/connect/upgrade.md rename to products/connect/guides/upgrade.md index 62a76ced3..3c5a6e095 100644 --- a/build/transfers/connect/upgrade.md +++ b/products/connect/guides/upgrade.md @@ -18,8 +18,6 @@ This guide will help you migrate to the new version in just a few simple steps. These updates ensure better performance and a smoother integration experience. -For complete documentation on the previous version of Wormhole Connect, please refer to the [Wormhole Connect guide](/docs/build/transfers/connect/){target=\_blank}. - ## Update the Connect Package To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. @@ -177,7 +175,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { diff --git a/products/connect/overview.md b/products/connect/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/connect/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/connect/reference/.pages b/products/connect/reference/.pages new file mode 100644 index 000000000..1786952e3 --- /dev/null +++ b/products/connect/reference/.pages @@ -0,0 +1,3 @@ +title: Reference +nav: +- 'Support Matrix': support-matrix.md diff --git a/build/transfers/connect/features.md b/products/connect/reference/support-matrix.md similarity index 97% rename from build/transfers/connect/features.md rename to products/connect/reference/support-matrix.md index 844b75441..2ba6242ba 100644 --- a/build/transfers/connect/features.md +++ b/products/connect/reference/support-matrix.md @@ -43,7 +43,7 @@ This route appears if both of the following conditions are satisfied: ### Token Bridge Relayer {: #token-bridge-relayer} -On the [routes](/docs/build/transfers/connect/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. diff --git a/products/connect/tutorials/.pages b/products/connect/tutorials/.pages new file mode 100644 index 000000000..3d599f5b0 --- /dev/null +++ b/products/connect/tutorials/.pages @@ -0,0 +1,4 @@ +title: Tutorials +nav: +- 'Create a React Bridging App': 'react-dapp.md' + diff --git a/tutorials/connect/react-dapp.md b/products/connect/tutorials/react-dapp.md similarity index 91% rename from tutorials/connect/react-dapp.md rename to products/connect/tutorials/react-dapp.md index 600e3b2d9..cf8b8cb8b 100644 --- a/tutorials/connect/react-dapp.md +++ b/products/connect/tutorials/react-dapp.md @@ -52,7 +52,7 @@ npm install @wormhole-foundation/wormhole-connect ### Integrate Connect into the Application -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/build/transfers/connect/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: === "JavaScript" @@ -108,7 +108,7 @@ Now, we need to modify the default `App.js` file to integrate Wormhole Connect. ### Customize Wormhole Connect -To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/build/transfers/connect/configuration/#introduction){target=\_blank}. +To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. ### Run the Application @@ -130,26 +130,26 @@ To transfer tokens from Sui to Fuji in the Wormhole Connect interface: 2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network 3. Enter the amount of SUI tokens you wish to transfer - ![](/docs/images/tutorials/connect/react-dapp/connect-1.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) 4. Choose to view other routes - ![](/docs/images/tutorials/connect/react-dapp/connect-2.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) 5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) !!! note It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - ![](/docs/images/tutorials/connect/react-dapp/connect-3.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) 6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - ![](/docs/images/tutorials/connect/react-dapp/connect-4.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) 7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - ![](/docs/images/tutorials/connect/react-dapp/connect-5.webp) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. @@ -157,11 +157,11 @@ Once the transaction has been submitted, Wormhole Connect will display the progr After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -![](/docs/images/tutorials/connect/react-dapp/connect-6.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. -![](/docs/images/tutorials/connect/react-dapp/connect-7.webp) +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) ## Resources diff --git a/products/messaging/.pages b/products/messaging/.pages new file mode 100644 index 000000000..25c295f4a --- /dev/null +++ b/products/messaging/.pages @@ -0,0 +1,6 @@ +title: Messaging +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- tutorials diff --git a/products/messaging/get-started.md b/products/messaging/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/messaging/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/messaging/guides/.pages b/products/messaging/guides/.pages new file mode 100644 index 000000000..27a4ea44e --- /dev/null +++ b/products/messaging/guides/.pages @@ -0,0 +1,4 @@ +title: Guides +nav: +- 'Interact with Wormhole Relayers': wormhole-relayers.md +- 'Interact with Core Contracts': core-contracts.md \ No newline at end of file diff --git a/build/core-messaging/core-contracts.md b/products/messaging/guides/core-contracts.md similarity index 83% rename from build/core-messaging/core-contracts.md rename to products/messaging/guides/core-contracts.md index 876940960..92569429f 100644 --- a/build/core-messaging/core-contracts.md +++ b/products/messaging/guides/core-contracts.md @@ -12,15 +12,15 @@ Wormhole's Core Contracts, deployed on each supported blockchain network, enable While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. ## Prerequisites To interact with the Wormhole Core Contract, you'll need the following: -- The [address of the Core Contract](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on ## How to Interact with Core Contracts @@ -40,7 +40,7 @@ To send a message, regardless of the environment or chain, the Core Contract is The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: ```solidity - --8<-- 'code/build/core-messaging/core-contracts/sending.sol' + --8<-- 'code/products/messaging/guides/core-contracts/sending.sol' ``` ??? interface "Parameters" @@ -70,7 +70,7 @@ To send a message, regardless of the environment or chain, the Core Contract is ??? interface "Example" ```solidity - --8<-- 'code/build/core-messaging/core-contracts/sendMessageEVM.sol' + --8<-- 'code/products/messaging/guides/core-contracts/sendMessageEVM.sol' ``` View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. @@ -138,7 +138,7 @@ To send a message, regardless of the environment or chain, the Core Contract is `payload` ++"Vec"++ - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/learn/infrastructure/vaas#payload-types){target=\_blank} page. + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. --- @@ -164,14 +164,14 @@ To send a message, regardless of the environment or chain, the Core Contract is ??? interface "Example" ```rust - --8<-- 'code/build/core-messaging/core-contracts/sendMessageSolana.rs' + --8<-- 'code/products/messaging/guides/core-contracts/sendMessageSolana.rs' ``` View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/learn/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/learn/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -VAAs are [multicast](/docs/learn/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. ### Receiving Messages @@ -182,7 +182,7 @@ The way a message is received and handled depends on the environment. On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. ```solidity - --8<-- 'code/build/core-messaging/core-contracts/receiving.sol' + --8<-- 'code/products/messaging/guides/core-contracts/receiving.sol' ``` ??? interface "Parameters" @@ -195,7 +195,7 @@ The way a message is received and handled depends on the environment. `vm` ++"VM memory"++ - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/learn/infrastructure/vaas/) page. + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. ??? child "Struct `VM`" @@ -232,7 +232,7 @@ The way a message is received and handled depends on the environment. ??? interface "Example" ```solidity - --8<-- 'code/build/core-messaging/core-contracts/receiveMessageEVM.sol' + --8<-- 'code/products/messaging/guides/core-contracts/receiveMessageEVM.sol' ``` View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. @@ -251,7 +251,7 @@ The way a message is received and handled depends on the environment. ??? interface "Example" ```rust - --8<-- 'code/build/core-messaging/core-contracts/receiveMessageSolana.rs' + --8<-- 'code/products/messaging/guides/core-contracts/receiveMessageSolana.rs' ``` View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. @@ -269,15 +269,15 @@ require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. ```typescript ---8<-- 'code/build/core-messaging/core-contracts/receiveEmitterCheck.ts' +--8<-- 'code/products/messaging/guides/core-contracts/receiveEmitterCheck.ts' ``` #### Additional Checks -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/learn/infrastructure/vaas/){target=\_blank}, including: +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. diff --git a/build/core-messaging/wormhole-relayers.md b/products/messaging/guides/wormhole-relayers.md similarity index 91% rename from build/core-messaging/wormhole-relayers.md rename to products/messaging/guides/wormhole-relayers.md index f8d17a11d..a536c1922 100644 --- a/build/core-messaging/wormhole-relayers.md +++ b/products/messaging/guides/wormhole-relayers.md @@ -8,18 +8,18 @@ categories: Relayers, Basics ## Introduction -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/infrastructure/relayers/run-relayer/) is available for more complex needs. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. ## Get Started with the Wormhole Relayer -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/build/start-building/supported-networks/) page. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.
- ![Wormhole Relayer](/docs/images/build/core-messaging/wormhole-relayers/relayer-1.webp) + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp)
The components outlined in blue must be implemented.
@@ -37,12 +37,12 @@ To start interacting with the Wormhole relayer in your contracts, you'll need to To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/build/reference/contract-addresses/#wormhole-relayer) reference page. +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. Your initial set up should resemble the following: ```solidity ---8<-- 'code/build/core-messaging/wormhole-relayers/ExampleContract.sol' +--8<-- 'code/products/messaging/guides/wormhole-relayers/ExampleContract.sol' ``` The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. @@ -52,7 +52,7 @@ The code provided sets up the basic structure for your contract to interact with To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. ```solidity ---8<-- 'code/build/core-messaging/wormhole-relayers/sendPayloadToEvm.sol' +--8<-- 'code/products/messaging/guides/wormhole-relayers/sendPayloadToEvm.sol' ``` !!! tip @@ -61,7 +61,7 @@ To send a message to a contract on another EVM chain, you can call the `sendPayl The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. ```solidity ---8<-- 'code/build/core-messaging/wormhole-relayers/quoteEVMDeliveryPrice.sol' +--8<-- 'code/products/messaging/guides/wormhole-relayers/quoteEVMDeliveryPrice.sol' ``` This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. @@ -69,7 +69,7 @@ This method should be called before sending a message, and the value returned fo In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: ```solidity ---8<-- 'code/build/core-messaging/wormhole-relayers/getQuoteAndSend.sol' +--8<-- 'code/products/messaging/guides/wormhole-relayers/getQuoteAndSend.sol' ``` ### Receive a Message @@ -77,7 +77,7 @@ In total, sending a message across EVM chains can be as simple as getting a fee To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). ```solidity ---8<-- 'code/build/core-messaging/wormhole-relayers/receiveWormholeMessages.sol' +--8<-- 'code/products/messaging/guides/wormhole-relayers/receiveWormholeMessages.sol' ``` The logic inside the function body may be whatever business logic is required to take action on the specific payload. @@ -142,4 +142,4 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and ## Step-by-Step Tutorial -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/tutorials/solidity-sdk/cross-chain-contracts/) tutorial. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. diff --git a/products/messaging/overview.md b/products/messaging/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/messaging/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/messaging/tutorials/.pages b/products/messaging/tutorials/.pages new file mode 100644 index 000000000..5a1cfbbdf --- /dev/null +++ b/products/messaging/tutorials/.pages @@ -0,0 +1,4 @@ +title: Tutorials +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md \ No newline at end of file diff --git a/tutorials/solidity-sdk/cross-chain-contracts.md b/products/messaging/tutorials/cross-chain-contracts.md similarity index 83% rename from tutorials/solidity-sdk/cross-chain-contracts.md rename to products/messaging/tutorials/cross-chain-contracts.md index 8f7d51a0b..62b417d3e 100644 --- a/tutorials/solidity-sdk/cross-chain-contracts.md +++ b/products/messaging/tutorials/cross-chain-contracts.md @@ -19,11 +19,11 @@ This tutorial assumes a basic understanding of Solidity and smart contract devel ## Wormhole Overview -We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/learn/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. +We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) ## Prerequisites @@ -57,7 +57,7 @@ Key functions include: Here's the core of the contract: ```solidity ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-1.sol:24:43" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-1.sol:24:43" ``` You can find the full code for the `MessageSender.sol` below. @@ -65,7 +65,7 @@ You can find the full code for the `MessageSender.sol` below. ??? code "MessageSender.sol" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-1.sol" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-1.sol" ``` ### Receiver Contract: MessageReceiver @@ -83,8 +83,8 @@ Key implementation details include: - **`isRegisteredSender`** - restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication ```solidity ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol:12:13" ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol:22:39" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol:12:13" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol:22:39" ``` #### Message Processing @@ -92,7 +92,7 @@ Key implementation details include: The `receiveWormholeMessages` is the core function that processes the received message. It checks that the Wormhole relayer sent the message, decodes the payload, and emits an event with the message content. It is essential to verify the message sender to prevent unauthorized messages. ```solidity ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol:42:64" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol:42:64" ``` You can find the full code for the `MessageReceiver.sol` below. @@ -100,7 +100,7 @@ You can find the full code for the `MessageReceiver.sol` below. ??? code "MessageReceiver.sol" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-2.sol" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-2.sol" ``` ## Deploy Contracts @@ -174,7 +174,7 @@ The repository includes: The expected output should be similar to this: ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-7.html" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-7.html" ### Deployment Process @@ -185,36 +185,36 @@ Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the === "`chains.json`" ```json - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-9.json" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-9.json" ``` === "`deploySender.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts:14:25" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts:14:25" ``` === "`deployReceiver.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts:14:25" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts:14:25" ``` !!! note - The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/build/reference/){target=\_blank}. + The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/contract-addresses/){target=\_blank}. 2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction === "`deploySender.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts:33:34" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts:33:34" ``` === "`deployReceiver.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts:31:32" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts:31:32" ``` 3. **Deploy the contract** - the contract is deployed to the network specified in the configuration. Upon successful deployment, the contract address is returned, which is crucial for interacting with the contract later on @@ -222,13 +222,13 @@ Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the === "`deploySender.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts:50:53" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts:50:53" ``` === "`deployReceiver.ts`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts:51:54" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts:51:54" ``` 4. **Register the `MessageSender` on the target chain** - after you deploy the `MessageReceiver` contract on the Celo Alfajores network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed @@ -236,7 +236,7 @@ Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts:67:81" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts:67:81" ``` You can find the full code for the `deploySender.ts` and `deployReceiver.ts` below. @@ -244,13 +244,13 @@ You can find the full code for the `deploySender.ts` and `deployReceiver.ts` bel ??? code "deploySender.ts" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-5.ts" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-5.ts" ``` ??? code "deployReceiver.ts" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-6.ts" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-6.ts" ``` ### Deploy the Sender Contract @@ -265,7 +265,7 @@ The sender contract will handle quoting and sending messages cross-chain. 2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\_blank} ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-8.html" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-8.html" ### Deploy the Receiver Contract @@ -295,7 +295,7 @@ Let's break down the script step by step. 2. **`deployedContracts.json`** - stores the addresses of the deployed sender and receiver contracts. This file is dynamically updated when contracts are deployed, but users can also manually add their own deployed contract addresses if needed ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:11:23" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:11:23" ``` 2. **Configure the provider and signer** - the script first reads the chain configurations and extracts the contract addresses. One essential step in interacting with a blockchain is setting up a _provider_. A provider is your connection to the blockchain network. It allows your script to interact with the blockchain, retrieve data, and send transactions. In this case, we're using a JSON-RPC provider @@ -303,31 +303,31 @@ Let's break down the script step by step. Next, we configure the wallet, which will be used to sign transactions. The wallet is created using the private key and the provider. This ensures that all transactions sent from this wallet are broadcast to the Avalanche Fuji network: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:47:48" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:47:48" ``` After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:51:56" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:51:56" ``` 3. **Set up the message details** - the next part of the script defines the target chain (Celo) and the target address (the receiver contract on Celo): ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:68:69" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:68:69" ``` You can customize the message that will be sent across chains: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:72:72" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:72:72" ``` 4. **Estimate cross-chain cost** - before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:75:75" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:75:75" ``` This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message. @@ -335,13 +335,13 @@ Let's break down the script step by step. 5. **Send a message** - with everything set up, the message is sent using the `sendMessage` function: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:78:85" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:78:85" ``` After sending, the script waits for the transaction to be confirmed: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts:88:88" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts:88:88" ``` 6. **Run the script** - to send the message, run the following command: @@ -354,14 +354,14 @@ If everything is set up correctly, the message will be sent from the Avalanche F The console should output something similar to this: ---8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-4.html" +--8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-4.html" You can find the full code for the `sendMessage.ts` below. ??? code "sendMessage.ts" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-contracts/snippet-3.ts" + --8<-- "code/products/messaging/tutorials/cross-chain-contracts/snippet-3.ts" ``` ## Conclusion diff --git a/tutorials/solidity-sdk/cross-chain-token-contracts.md b/products/messaging/tutorials/cross-chain-token-contracts.md similarity index 86% rename from tutorials/solidity-sdk/cross-chain-token-contracts.md rename to products/messaging/tutorials/cross-chain-token-contracts.md index 747cb5205..f540c99df 100644 --- a/tutorials/solidity-sdk/cross-chain-token-contracts.md +++ b/products/messaging/tutorials/cross-chain-token-contracts.md @@ -54,7 +54,7 @@ To simplify this process, we've included a tool for verifying if a token has an 5. The expected output when the token has an attestation: - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-10.html" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-10.html" Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process. @@ -111,8 +111,8 @@ Let's start writing the `CrossChainSender` contract: 2. Open the file. First, we'll start with the imports and the contract setup: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol:1:14" - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol:58:58" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol:1:14" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol:58:58" ``` This sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. @@ -122,7 +122,7 @@ Let's start writing the `CrossChainSender` contract: 3. Next, let's add a function that estimates the cost of sending tokens across chains: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol:17:28" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol:17:28" ``` This function, `quoteCrossChainDeposit`, helps calculate the cost of transferring tokens to a different chain. It factors in the delivery cost and the cost of publishing a message via the Wormhole protocol. @@ -130,7 +130,7 @@ Let's start writing the `CrossChainSender` contract: 4. Finally, we'll add the function that sends the tokens across chains: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol:31:57" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol:31:57" ``` This `sendCrossChainDeposit` function is where the actual token transfer happens. It sends the tokens to the recipient on the target chain using the Wormhole protocol. @@ -157,7 +157,7 @@ You can find the complete code for the `CrossChainSender.sol` below. ??? code "MessageSender.sol" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-1.sol" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-1.sol" ``` ### Receiver Contract: CrossChainReceiver @@ -175,8 +175,8 @@ Let's start writing the `CrossChainReceiver` contract: 2. Open the file. First, we'll start with the imports and the contract setup: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol:1:14" - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol:40:40" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol:1:14" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol:40:40" ``` Similar to the `CrossChainSender` contract, this sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. @@ -184,7 +184,7 @@ Let's start writing the `CrossChainReceiver` contract: 3. Next, let's add a function inside the contract to handle receiving the payload and tokens: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol:17:39" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol:17:39" ``` This `receivePayloadAndTokens` function processes the tokens and payload sent from another chain, decodes the recipient address, and transfers the tokens to them using the Wormhole protocol. This function also validates the emitter (`sourceAddress`) to ensure the message comes from a trusted sender. @@ -195,14 +195,14 @@ Let's start writing the `CrossChainReceiver` contract: - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface -After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/learn/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. +After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. ??? tip "Understanding the `TokenReceived` Struct" Let’s delve into the fields provided to us in the `TokenReceived` struct: ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-11.sol" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-11.sol" ``` - **`tokenHomeAddress`** - the original address of the token on its native chain. This is the same as the token field in the call to `sendTokenWithPayloadToEvm` unless the original token sent is a Wormhole-wrapped token. In that case, this will be the address of the original version of the token (on its native chain) in Wormhole address format (left-padded with 12 zeros) @@ -220,7 +220,7 @@ You can find the complete code for the `CrossChainReceiver.sol` contract below: ??? code "CrossChainReceiver.sol" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-2.sol" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-2.sol" ``` ## Deploy the Contracts @@ -244,12 +244,12 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 3. Open the `config.json` file and add the following configuration: ```json - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-3.json" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-3.json" ``` This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. - For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/build/reference/contract-addresses/){target=_blank}. + For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. !!! note You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. @@ -290,7 +290,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract The expected output should be similar to this: - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-6.html" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-6.html" 4. **Write the deployment script** - you’ll need a script to automate the deployment of your contracts. Let’s create the deployment script @@ -303,7 +303,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 2. Open the file and load imports and configuration: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:1:7" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:1:7" ``` Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal. @@ -311,7 +311,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 3. Define interfaces to use for chain configuration and contract deployment: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:9:25" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:9:25" ``` These interfaces define the structure of the chain configuration and the contract deployment details. @@ -319,7 +319,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 4. Load and select the chains for deployment: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:27:47" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:27:47" ``` The `loadConfig` function reads the chain configuration from the `config.json` file, and the `selectChain` function allows the user to choose the source and target chains for deployment interactively. The user is prompted in the terminal to select which chains to use, making the process interactive and user-friendly. @@ -327,7 +327,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 5. Define the main function for deployment and load the chain configuration: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:48:53" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:48:53" ``` - The `main` function is the entry point for the deployment script @@ -336,7 +336,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 6. Set up provider and wallet: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:54:57" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:54:57" ``` The scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction on the source chain. @@ -344,7 +344,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 7. Read the compiled contracts: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:58:66" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:58:66" ``` - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract @@ -354,7 +354,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 8. Extract the contract ABI and bytecode: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:68:69" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:68:69" ``` - **ABI (Application Binary Interface)** - defines the structure of the contract’s functions, events, and data types, allowing the front end to interact with the contract on the blockchain @@ -363,7 +363,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 9. Create the Contract Factory: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:71:75" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:71:75" ``` - **`ethers.ContractFactory`** - creates a new contract factory using the ABI, bytecode, and a wallet (representing the signer). The contract factory is responsible for deploying instances of the contract to the blockchain @@ -373,12 +373,12 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract === "`CrossChainSender`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:77:83" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:77:83" ``` === "`CrossChainReceiver`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:91:115" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:91:115" ``` Both functions deploy the respective contracts to the selected chains. @@ -394,12 +394,12 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract === "`senderAddress`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:86:89" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:86:89" ``` === "`receiverAddress`" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:118:121" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:118:121" ``` You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference. @@ -407,7 +407,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 12. Register the `CrossChainSender` address on the target chain: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:128:139" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:128:139" ``` After you deploy the `CrossChainReceiver` contract on the target network, the sender contract address from the source chain needs to be registered. This ensures that only messages from the registered `CrossChainSender` contract are processed. @@ -418,7 +418,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract ???- example "Save Deployment Details Example" ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:145:185" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:145:185" ``` Add your desired logic to save the deployed contract addresses in a JSON file (or another format). This will be important later when transferring tokens, as you'll need these addresses to interact with the deployed contracts. @@ -426,7 +426,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract 14. Handle errors and finalize the script: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts:186:201" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts:186:201" ``` The try-catch block wraps the deployment logic to catch any errors that may occur. @@ -441,7 +441,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract ??? code "deploy.ts" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-4.ts" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-4.ts" ``` 5. **Add your private key** - you'll need to provide your private key. It allows your deployment script to sign the transactions that deploy the smart contracts to the blockchain. Without it, the script won't be able to interact with the blockchain on your behalf @@ -475,7 +475,7 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract If you followed the logic provided in the full code above, your terminal output should look something like this: ---8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-7.html" +--8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-7.html" ## Transfer Tokens Across Chains @@ -499,7 +499,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` 2. Open the file. Start with the necessary imports, interfaces and configurations: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:1:25" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:1:25" ``` These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input. @@ -508,7 +508,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:27:47" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:27:47" ``` These functions load the network and contract details that were saved during deployment. @@ -518,7 +518,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` Refer to the deployed contracts and create logic as desired. In our example, we made this process interactive, allowing users to select the source and target chains from all the historically deployed contracts. This interactive approach helps ensure the correct chains are selected for the token transfer. ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:49:101" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:49:101" ``` 2. **Implement the token transfer logic** @@ -526,7 +526,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` 1. Start the `main` function: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:103:139" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:103:139" ``` The `main` function is where the token transfer logic will reside. It loads the chain and contract details, sets up the wallet and provider, and loads the `CrossChainSender` contract. @@ -536,7 +536,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` You'll now ask the user for the token contract address, the recipient address on the target chain, and the amount of tokens to transfer. ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:147:171" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:147:171" ``` This section of the script prompts the user for the token contract address and the recipient's address, fetches the token's decimal value, and parses the amount accordingly. @@ -546,7 +546,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` Finally, initiate the cross-chain transfer and log the details. ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:174:204" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:174:204" ``` This part of the script first approves the token transfer, then initiates the cross-chain transfer using the `CrossChainSender` contract, and finally logs the transaction hash for the user to track. @@ -554,7 +554,7 @@ In this step, you'll write a script to transfer tokens across chains using the ` 4. Finalize the script: ```typescript - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts:205:208" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts:205:208" ``` This section finalizes the script by calling the `main` function and handling any errors that may occur during the token transfer process. @@ -564,7 +564,7 @@ You can find the full code for the `transfer.ts` file below: ??? code "transfer.ts" ```solidity - --8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-5.ts" + --8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-5.ts" ``` ### Transfer Tokens @@ -589,7 +589,7 @@ You can verify the transaction on the [Wormhole Explorer](https://wormholescan.i If you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this: ---8<-- "code/tutorials/solidity-sdk/cross-chain-token-transfers/snippet-8.html" +--8<-- "code/products/messaging/tutorials/cross-chain-token-transfers/snippet-8.html" !!! note In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. We sent two units of USDC Testnet tokens using the token contract address `0x5425890298aed601595a70ab815c96711a31bc65`. You can replace these details with those relevant to your project or use the same for testing purposes. diff --git a/tutorials/wormholescan/replace-signatures.md b/products/messaging/tutorials/replace-signatures.md similarity index 80% rename from tutorials/wormholescan/replace-signatures.md rename to products/messaging/tutorials/replace-signatures.md index 1ae76cfe2..cb256eb58 100644 --- a/tutorials/wormholescan/replace-signatures.md +++ b/products/messaging/tutorials/replace-signatures.md @@ -9,7 +9,7 @@ description: Learn how to fetch, validate, and replace outdated signatures in Wo ## Introduction -Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. +Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. @@ -57,7 +57,7 @@ In this section, you will create the directory, initialize a Node.js project, in Then, add the following configuration: ```json title="tsconfig.json" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-1.json" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-1.json" ``` 4. **Install dependencies** - add the required packages @@ -87,19 +87,19 @@ In this section, you will create the directory, initialize a Node.js project, in 6. **Set variables** - define key constants in `src/config/constants.ts` ```bash title="src/config/constants.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-2.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-2.ts" ``` - **`RPC`** - endpoint for interacting with an Ethereum RPC node - - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs + - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts - **`TXS`** - list of example transaction hashes that will be used for testing -7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs +7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs ```typescript title="src/config/layouts.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-3.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-3.ts" ``` ## Create VAA Handling Functions @@ -109,7 +109,7 @@ In this section, we'll create a series of helper functions in the `src/helpers/v To get started, import the necessary dependencies: ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:1:15" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:1:15" ``` ### Fetch a VAA ID from a Transaction @@ -121,7 +121,7 @@ The VAA ID is structured as follows: chain/emitter/sequence ``` - - `chain` - the [Wormhole chain ID](/docs/build/reference/chain-ids/){target=\_blank} (Ethereum is 2) + - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) - `emitter` - the contract address that emitted the VAA - `sequence` - a unique identifier for the event @@ -138,7 +138,7 @@ Follow the below steps to process the transaction logs and construct the VAA ID: 4. **Construct the VAA ID** - format the extracted data in `chain/emitter/sequence` format ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:17:50" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:17:50" ``` ???- code "Try it out: VAA ID retrieval" @@ -153,7 +153,7 @@ Follow the below steps to process the transaction logs and construct the VAA ID: 2. **Add the function call** ```typescript title="test/fetchVaaId.run.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-5.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-5.ts" ``` 3. **Run the script** @@ -164,7 +164,7 @@ Follow the below steps to process the transaction logs and construct the VAA ID: If successful, the output will be: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-6.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-6.html" If no VAA ID is found, the script will log an error message. @@ -175,7 +175,7 @@ Now that you have the VAA ID, we can use it to fetch the full VAA payload from t Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload. ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:52:67" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:52:67" ``` ???- code "Try it out: VAA retrieval" @@ -190,7 +190,7 @@ Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate 2. **Add the function call** ```typescript title="test/fetchVaa.run.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-7.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-7.ts" ``` 3. **Run the script** @@ -201,7 +201,7 @@ Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate If successful, the output will be: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-8.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-8.html" If no VAA is found, the script will log an error message. @@ -220,7 +220,7 @@ Follow these steps to implement the function: 3. **Decode the response** - check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:69:107" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:69:107" ``` ???- code "Try it out: VAA Validity" @@ -235,7 +235,7 @@ Follow these steps to implement the function: 2. **Add the function call** ```typescript title="test/checkVaaValidity.run.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-9.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-9.ts" ``` 3. **Run the script** @@ -246,11 +246,11 @@ Follow these steps to implement the function: If the VAA is valid, the output will be: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-10.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-10.html" If invalid, the output will include the reason: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-11.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-11.html" ### Fetch Observations (VAA Signatures) @@ -259,7 +259,7 @@ Before replacing outdated signatures, we need to fetch the original VAA signatur Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to query the Wormholescan API for observations related to a given VAA. Format the response by converting Guardian addresses to lowercase for consistency, and return an empty array if an error occurs. ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:109:125" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:109:125" ``` ???- code "Try it out: Fetch Observations" @@ -274,7 +274,7 @@ Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to 2. **Add the function call** ```typescript title="test/fetchObservations.run.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-12.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-12.ts" ``` 3. **Run the script** @@ -285,7 +285,7 @@ Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to If successful, the output will be: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-13.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-13.html" If no observations are found, the script will log an error message. @@ -296,7 +296,7 @@ Now that we have the original VAA signatures, we must fetch the latest Guardian Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set. ```typescript title="src/helpers/vaaHelper.ts" ---8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:126:142" +--8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:126:142" ``` ???- code "Try it out: Fetch Guardian Set" @@ -311,7 +311,7 @@ Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fe 2. **Add the function call** ```typescript title="test/fetchGuardianSet.run.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-14.ts" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-14.ts" ``` 3. **Run the script** @@ -322,7 +322,7 @@ Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fe If successful, the output will be: - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-15.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-15.html" If an error occurs while fetching the Guardian set, a `500` status error will be logged. @@ -333,9 +333,9 @@ With the full VAA, Guardian signatures, and the latest Guardian set, we can now 1. **Create the `replaceSignatures()` function** - open `src/helpers/vaaHelper.ts` and add the function header. To catch and handle errors properly, all logic will be wrapped inside a `try` block ```typescript title="src/helpers/vaaHelper.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:144:152" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:144:152" // Add logic in the following steps here - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:280:283" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:280:283" ``` - **`vaa`** - original VAA bytes @@ -346,54 +346,54 @@ With the full VAA, Guardian signatures, and the latest Guardian set, we can now 2. **Validate input data** - ensure all required parameters are present before proceeding. If any required input is missing, the function throws an error to prevent execution with incomplete data. The Guardian set should never be empty; if it is, this likely indicates an error in fetching the Guardian set in a previous step ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:153:156" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:153:156" ``` 3. **Filter valid signatures** - remove signatures from inactive Guardians, keeping only valid ones. If there aren't enough valid signatures to replace the outdated ones, execution is halted to prevent an incomplete or invalid VAA ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:158:163" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:158:163" ``` 4. **Convert valid signatures** - ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:165:195" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:165:195" ``` 5. **Deserialize the VAA** - convert the raw VAA data into a structured format for further processing ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:197:202" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:197:202" ``` 6. **Identify outdated signatures** - compare the current VAA signatures with the newly formatted ones to detect which signatures belong to outdated Guardians. Remove these outdated signatures to ensure only valid ones remain ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:204:217" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:204:217" ``` 7. **Replace outdated signatures** - substitute outdated signatures with valid ones while maintaining the correct number of signatures. If there aren’t enough valid replacements, execution stops ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:219:237" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:219:237" ``` 8. **Serialize the updated VAA** - reconstruct the VAA with the updated signatures and convert it into a format suitable for submission ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:239:250" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:239:250" ``` 9. **Send the updated VAA for verification and handle errors** - submit the updated VAA to an Ethereum RPC node for validation, ensuring it can be proposed for Guardian approval. If an error occurs during submission or signature replacement, log the issue and prevent further execution ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:252:279" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:252:279" ``` ???- code "Complete Function" ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-4.ts:144:283" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-4.ts:144:283" ``` ## Create Script to Replace Outdated VAA Signatures @@ -403,19 +403,19 @@ Now that we have all the necessary helper functions, we will create a script to 1. **Open the file** - inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs ```typescript title="src/scripts/replaceSignatures.ts" - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-16.ts:1:9" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-16.ts:1:9" ``` 2. **Define the main execution function** - add the following function inside `src/scripts/replaceSignatures.ts` to process each transaction in `TXS`, going step by step through the signature replacement process ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-16.ts:11:51" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-16.ts:11:51" ``` 3. **Make the script executable** - ensure it runs when executed ```typescript - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-16.ts:53:53" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-16.ts:53:53" ``` To run the script, use the following command: @@ -424,7 +424,7 @@ Now that we have all the necessary helper functions, we will create a script to npx tsx src/scripts/replaceSignatures.ts ``` - --8<-- "code/tutorials/wormholescan/replace-signatures/replace-sigs-17.html" + --8<-- "code/products/messaging/tutorials/replace-signatures/replace-sigs-17.html" The script logs each step, skipping valid VAAs, replacing outdated signatures for invalid VAAs, and logging any errors. It then completes with a valid VAA ready for submission. diff --git a/products/multigov/.pages b/products/multigov/.pages new file mode 100644 index 000000000..515cb66d0 --- /dev/null +++ b/products/multigov/.pages @@ -0,0 +1,8 @@ +title: MultiGov +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- tutorials +- concepts +- 'FAQs': faqs.md diff --git a/products/multigov/concepts/.pages b/products/multigov/concepts/.pages new file mode 100644 index 000000000..9ef6dde62 --- /dev/null +++ b/products/multigov/concepts/.pages @@ -0,0 +1,3 @@ +title: Concepts +nav: +- 'Architecture': architecture.md \ No newline at end of file diff --git a/learn/governance/architecture.md b/products/multigov/concepts/architecture.md similarity index 98% rename from learn/governance/architecture.md rename to products/multigov/concepts/architecture.md index 85dbdde1e..587f87412 100644 --- a/learn/governance/architecture.md +++ b/products/multigov/concepts/architecture.md @@ -126,4 +126,4 @@ MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensu This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. -![detailed multigov architecture diagram](/docs/images/learn/governance/multigov-detailed.webp) +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) diff --git a/build/multigov/faq.md b/products/multigov/faqs.md similarity index 71% rename from build/multigov/faq.md rename to products/multigov/faqs.md index 2dd2f401a..a1f8786ec 100644 --- a/build/multigov/faq.md +++ b/products/multigov/faqs.md @@ -1,14 +1,16 @@ --- -title: MultiGov Technical FAQs +title: MultiGov FAQs description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. categories: MultiGov --- # FAQs -## Technical Questions +## What is MultiGov? -### How does MultiGov ensure security in cross-chain communication? +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. + +## How does MultiGov ensure security in cross-chain communication? MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: @@ -17,42 +19,38 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl - Authorized participant validation to maintain the integrity of the governance process - Replay attack prevention by tracking executed messages -### Can MultiGov integrate with any blockchain? +## Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/build/start-building/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. -### How are votes aggregated across different chains? +## How are votes aggregated across different chains? Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. -### Can governance upgrade from a single chain to MultiGov? +## Can governance upgrade from a single chain to MultiGov? Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. -## Usage Questions - -### How can I create a proposal in MultiGov? +## How can I create a proposal in MultiGov? Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. -### How do I vote on a proposal if I hold tokens on a spoke chain? +## How do I vote on a proposal if I hold tokens on a spoke chain? You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. -### How are approved proposals executed across multiple chains? +## How are approved proposals executed across multiple chains? When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. -## Implementation Questions - -### What are the requirements for using MultiGov? +## What are the requirements for using MultiGov? To use MultiGov, your DAO must meet the following requirements: - **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance - **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature -### What do I need to set up MultiGov for my project? +## What do I need to set up MultiGov for my project? Get started by filling out the form below: @@ -67,17 +65,17 @@ To set up testing MultiGov for your DAO, you'll need: - Modify and deploy the hub and spoke contracts using the provided scripts - Set up the necessary environment variables and configurations -### Can MultiGov be used with non-EVM chains? +## Can MultiGov be used with non-EVM chains? The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. -### How can I customize voting parameters in MultiGov? +## How can I customize voting parameters in MultiGov? Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. -### How does MultiGov handle potential network issues or temporary chain unavailability? +## How does MultiGov handle potential network issues or temporary chain unavailability? MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: @@ -86,4 +84,17 @@ MultiGov includes several mechanisms to handle network issues or temporary chain 3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through 4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline -However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. \ No newline at end of file +However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. + +## How does MultiGov differ from traditional DAO governance? + +Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. + +## What are the main components of MultiGov? + +The main components of MultiGov include: + +- **Hub chain** - central coordination point for governance activities +- **Spoke chains** - additional chains where token holders can participate in governance +- **Wormhole integration** - enables secure cross-chain message passing +- **Governance token** - allows holders to participate in governance across all integrated chains diff --git a/products/multigov/get-started.md b/products/multigov/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/multigov/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/multigov/guides/.pages b/products/multigov/guides/.pages new file mode 100644 index 000000000..cc8edf95d --- /dev/null +++ b/products/multigov/guides/.pages @@ -0,0 +1,6 @@ +title: Guides +nav: +- 'Deploy to EVM Chains': deploy-to-evm.md +- 'Deploy to Solana': deploy-to-solana.md +- 'Upgrade on EVM Chains': upgrade-evm.md +- 'Upgrade on Solana': upgrade-solana.md diff --git a/build/multigov/deploy-to-evm.md b/products/multigov/guides/deploy-to-evm.md similarity index 98% rename from build/multigov/deploy-to-evm.md rename to products/multigov/guides/deploy-to-evm.md index ad98f96ac..ccb809ea8 100644 --- a/build/multigov/deploy-to-evm.md +++ b/products/multigov/guides/deploy-to-evm.md @@ -6,7 +6,7 @@ categories: MultiGov # Deploy MultiGov on EVM Chains -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/build/multigov/){target=\_blank}. +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. diff --git a/build/multigov/deploy-to-solana.md b/products/multigov/guides/deploy-to-solana.md similarity index 98% rename from build/multigov/deploy-to-solana.md rename to products/multigov/guides/deploy-to-solana.md index 78855bee5..4fc956d99 100644 --- a/build/multigov/deploy-to-solana.md +++ b/products/multigov/guides/deploy-to-solana.md @@ -6,7 +6,7 @@ categories: MultiGov # Deploy MultiGov on Solana -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/learn/governance/architecture/){target=\_blank}. +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. diff --git a/build/multigov/upgrade-evm.md b/products/multigov/guides/upgrade-evm.md similarity index 100% rename from build/multigov/upgrade-evm.md rename to products/multigov/guides/upgrade-evm.md diff --git a/build/multigov/upgrade-solana.md b/products/multigov/guides/upgrade-solana.md similarity index 100% rename from build/multigov/upgrade-solana.md rename to products/multigov/guides/upgrade-solana.md diff --git a/products/multigov/overview.md b/products/multigov/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/multigov/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/multigov/tutorials/.pages b/products/multigov/tutorials/.pages new file mode 100644 index 000000000..7ffdc370f --- /dev/null +++ b/products/multigov/tutorials/.pages @@ -0,0 +1,3 @@ +title: Tutorials +nav: +- 'Create a Treasury Management Proposal': treasury-proposal.md diff --git a/tutorials/multigov/treasury-proposal.md b/products/multigov/tutorials/treasury-proposal.md similarity index 100% rename from tutorials/multigov/treasury-proposal.md rename to products/multigov/tutorials/treasury-proposal.md diff --git a/products/native-token-transfers/.pages b/products/native-token-transfers/.pages new file mode 100644 index 000000000..69372bf1f --- /dev/null +++ b/products/native-token-transfers/.pages @@ -0,0 +1,10 @@ +title: Native Token Transfers +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- configuration +- guides +- concepts +- 'Troubleshooting': troubleshooting.md +- 'FAQs': faqs.md +- reference diff --git a/products/native-token-transfers/concepts/.pages b/products/native-token-transfers/concepts/.pages new file mode 100644 index 000000000..1e4ae1c43 --- /dev/null +++ b/products/native-token-transfers/concepts/.pages @@ -0,0 +1,4 @@ +title: Concepts +nav: +- 'Architecture': architecture.md +- 'Security': security.md \ No newline at end of file diff --git a/learn/transfers/native-token-transfers/architecture.md b/products/native-token-transfers/concepts/architecture.md similarity index 96% rename from learn/transfers/native-token-transfers/architecture.md rename to products/native-token-transfers/concepts/architecture.md index 9c80c7c9a..f04d3693b 100644 --- a/learn/transfers/native-token-transfers/architecture.md +++ b/products/native-token-transfers/concepts/architecture.md @@ -49,10 +49,10 @@ How it works: 2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred 3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain -![NTT architecture diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-1.webp) +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) !!! note - [Learn more](/docs/learn/transfers/native-token-transfers/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. #### Custom Transceivers @@ -60,7 +60,7 @@ The NTT framework supports advanced features such as custom transceivers for spe NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -![Custom Attestation with NTT diagram](/docs/images/learn/transfers/native-token-transfers/architecture/architecture-2.webp) +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. diff --git a/learn/transfers/native-token-transfers/security.md b/products/native-token-transfers/concepts/security.md similarity index 100% rename from learn/transfers/native-token-transfers/security.md rename to products/native-token-transfers/concepts/security.md diff --git a/products/native-token-transfers/configuration/.pages b/products/native-token-transfers/configuration/.pages new file mode 100644 index 000000000..e54bd132d --- /dev/null +++ b/products/native-token-transfers/configuration/.pages @@ -0,0 +1,4 @@ +title: Configuration +nav: +- 'Access Control': 'access-control.md' +- 'Rate Limits': 'rate-limiting.md' \ No newline at end of file diff --git a/build/transfers/native-token-transfers/configuration/access-control.md b/products/native-token-transfers/configuration/access-control.md similarity index 100% rename from build/transfers/native-token-transfers/configuration/access-control.md rename to products/native-token-transfers/configuration/access-control.md diff --git a/build/transfers/native-token-transfers/configuration/rate-limiting.md b/products/native-token-transfers/configuration/rate-limiting.md similarity index 100% rename from build/transfers/native-token-transfers/configuration/rate-limiting.md rename to products/native-token-transfers/configuration/rate-limiting.md diff --git a/build/transfers/native-token-transfers/faqs.md b/products/native-token-transfers/faqs.md similarity index 95% rename from build/transfers/native-token-transfers/faqs.md rename to products/native-token-transfers/faqs.md index 800e30482..89a7048e3 100644 --- a/build/transfers/native-token-transfers/faqs.md +++ b/products/native-token-transfers/faqs.md @@ -10,7 +10,7 @@ categories: NTT, Transfer Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. -Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/learn/transfers/native-token-transfers/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. +Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. ## What causes the "No protocols registered for Evm" error in Wormhole SDK? diff --git a/products/native-token-transfers/get-started.md b/products/native-token-transfers/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/native-token-transfers/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/native-token-transfers/guides/.pages b/products/native-token-transfers/guides/.pages new file mode 100644 index 000000000..19854a63c --- /dev/null +++ b/products/native-token-transfers/guides/.pages @@ -0,0 +1,5 @@ +title: Guides +nav: +- 'Deploy to EVM Chains': deploy-to-evm.md +- 'Deploy to EVM Chains via Launchpad': evm-launchpad.md +- 'Deploy to Solana': deploy-to-solana.md \ No newline at end of file diff --git a/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md b/products/native-token-transfers/guides/deploy-to-evm.md similarity index 93% rename from build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md rename to products/native-token-transfers/guides/deploy-to-evm.md index c88e45d2d..c02c531bd 100644 --- a/build/transfers/native-token-transfers/deployment-process/deploy-to-evm.md +++ b/products/native-token-transfers/guides/deploy-to-evm.md @@ -25,7 +25,7 @@ These functions aren't part of the standard ERC-20 interface. The [`INttToken` i ??? code "View the complete `INttToken` Interface`" ```solidity - --8<-- 'code/build/transfers/native-token-transfers/deployment-process/INttToken.sol' + --8<-- 'code/products/native-token-transfers/guides/deploy-to-evm/INttToken.sol' ``` Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. @@ -44,7 +44,7 @@ For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), th This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. -For more detailed information, see the [Deployment Models](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank} page. +For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. ### Key Differences Between Modes @@ -83,7 +83,7 @@ export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: ```bash ---8<-- 'code/build/transfers/native-token-transfers/deployment-process/initialize.txt' +--8<-- 'code/products/native-token-transfers/guides/deploy-to-evm/initialize.txt' ``` While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. @@ -141,4 +141,4 @@ The final step in the deployment process is to set the NTT Manager as a minter o By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. !!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. \ No newline at end of file + To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. \ No newline at end of file diff --git a/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md similarity index 86% rename from build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md rename to products/native-token-transfers/guides/deploy-to-solana.md index aaef5af8a..df75635cb 100644 --- a/build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -6,7 +6,7 @@ categories: NTT, Transfer # Deploy Native Token Transfers on Solana -[Native Token Transfers (NTT)](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. @@ -97,7 +97,7 @@ Deploying NTT with the CLI on Solana follows a structured process: !!! note NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -2. **Choose your [deployment model](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank}**: +2. **Choose your [deployment model](TODO){target=\_blank}**: - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program @@ -106,13 +106,13 @@ Deploying NTT with the CLI on Solana follows a structured process: Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -By default, NTT transfers to Solana require manual [relaying](/docs/learn/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. ## Set Up NTT To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -The [NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: 1. **Create a new NTT project** - set up a deployment workspace @@ -231,7 +231,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -239,7 +239,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Test Your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** @@ -247,6 +247,6 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. - [:custom-arrow: Use Connect to Integrate NTT](/docs/build/transfers/connect/){target=\_blank} + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} diff --git a/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md b/products/native-token-transfers/guides/evm-launchpad.md similarity index 73% rename from build/transfers/native-token-transfers/deployment-process/evm-launchpad.md rename to products/native-token-transfers/guides/evm-launchpad.md index 526014761..0e7fedf39 100644 --- a/build/transfers/native-token-transfers/deployment-process/evm-launchpad.md +++ b/products/native-token-transfers/guides/evm-launchpad.md @@ -52,11 +52,11 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Launch a Cross-Chain Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-2.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) 3. Set the token details: 1. Select the **home network** from the dropdown menu @@ -65,22 +65,22 @@ Deploy a new NTT-compatible token that can be transferred across multiple chains 4. Provide the **initial supply** 5. To the token details, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-3.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) 4. Select the deployment chains: 1. The home network where your token will be deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-4.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -92,33 +92,33 @@ Expand an existing token to support NTT across multiple chains. This process int 1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-1.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) 2. Select **Expand Your Existing Token** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-7.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) 3. Enter the token details: 1. Choose the home network where your token is already deployed (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 3. To continue, click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-8.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) 4. Select the chains to deploy your token to: 1. The home network where your token is already deployed will be populated (e.g., Optimism) 2. Choose any additional chains to deploy your token to (e.g., Base) 1. Click **Next** - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-9.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) 5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-5.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) 6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - ![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-6.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) 7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step @@ -128,7 +128,7 @@ Expand an existing token to support NTT across multiple chains. This process int To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-10.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) The dashboard provides a high-level view of your token across all deployed chains, including: @@ -136,7 +136,7 @@ The dashboard provides a high-level view of your token across all deployed chain - Supply distribution visualization - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-11.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) ## Settings @@ -151,27 +151,27 @@ From this section, you can also: - **Pause the token** – temporarily turn off transfers on the selected chain - **Deploy to a new chain** – expand your token by deploying it to an additional chain -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-12.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) ### Role Management -This section displays key [roles](/docs/build/transfers/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - **Manager’s Owner** – the owner through the `NTTOwner` proxy - **Pauser** – the address authorized to pause transfers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-13.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) ### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - **Registered Transceivers** – displays the number of registered transceivers and their addresses - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-14.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) ### Peer Chains Limits @@ -182,4 +182,4 @@ Define the transfer restrictions for each connected network. You can adjust: Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -![](/docs/images/build/transfers/native-token-transfers/deployment-process/evm-launchpad/ntt-launchpad-15.webp) +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) diff --git a/products/native-token-transfers/overview.md b/products/native-token-transfers/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/native-token-transfers/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/native-token-transfers/reference/.pages b/products/native-token-transfers/reference/.pages new file mode 100644 index 000000000..5793ccfb9 --- /dev/null +++ b/products/native-token-transfers/reference/.pages @@ -0,0 +1,3 @@ +title: Reference +nav: +- 'NTT CLI Commands': 'cli-commands.md' \ No newline at end of file diff --git a/build/transfers/native-token-transfers/cli-commands.md b/products/native-token-transfers/reference/cli-commands.md similarity index 92% rename from build/transfers/native-token-transfers/cli-commands.md rename to products/native-token-transfers/reference/cli-commands.md index 6881c85ef..e5d1bbc85 100644 --- a/build/transfers/native-token-transfers/cli-commands.md +++ b/products/native-token-transfers/reference/cli-commands.md @@ -10,7 +10,7 @@ categories: NTT, Transfer The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](/docs/build/transfers/native-token-transfers/deployment-process/installation/#installation){target=\_blank} to set it up before proceeding. +If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. ## Table of Commands @@ -59,7 +59,7 @@ To explore detailed information about any NTT CLI command, including its options Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. - [:custom-arrow: Configure your NTT deployment](/docs/build/transfers/native-token-transfers/configuration/) + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) - :octicons-question-16:{ .lg .middle } **NTT FAQs** @@ -67,6 +67,6 @@ To explore detailed information about any NTT CLI command, including its options Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Check out the FAQs](/docs/build/transfers/native-token-transfers/faqs/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) diff --git a/build/transfers/native-token-transfers/deployment-process/troubleshooting.md b/products/native-token-transfers/troubleshooting.md similarity index 87% rename from build/transfers/native-token-transfers/deployment-process/troubleshooting.md rename to products/native-token-transfers/troubleshooting.md index c5778cb52..c2a2fd7ae 100644 --- a/build/transfers/native-token-transfers/deployment-process/troubleshooting.md +++ b/products/native-token-transfers/troubleshooting.md @@ -8,15 +8,15 @@ categories: NTT, Transfer If you encounter issues during the NTT deployment process, check the following common points: -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#install-dependencies){target=\_blank} +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain - **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/build/transfers/native-token-transfers/deployment-process/deploy-to-evm/#configure-ntt){target=\_blank} + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} - **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file ???- interface "Dockerfile" diff --git a/build/start-building/products.md b/products/products.md similarity index 85% rename from build/start-building/products.md rename to products/products.md index 0775e6a53..4a8e41412 100644 --- a/build/start-building/products.md +++ b/products/products.md @@ -16,8 +16,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -55,4 +55,4 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Multichain Governance -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. \ No newline at end of file +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. \ No newline at end of file diff --git a/products/queries/.pages b/products/queries/.pages new file mode 100644 index 000000000..1f5a8dafb --- /dev/null +++ b/products/queries/.pages @@ -0,0 +1,8 @@ +title: Queries +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- concepts +- 'FAQs': faqs.md +- reference diff --git a/products/queries/concepts/.pages b/products/queries/concepts/.pages new file mode 100644 index 000000000..c2adbdd18 --- /dev/null +++ b/products/queries/concepts/.pages @@ -0,0 +1,3 @@ +title: Concepts +nav: +- 'RPC Basics': rpc-basics.md \ No newline at end of file diff --git a/products/queries/concepts/rpc-basics.md b/products/queries/concepts/rpc-basics.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/concepts/rpc-basics.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/build/queries/faqs.md b/products/queries/faqs.md similarity index 100% rename from build/queries/faqs.md rename to products/queries/faqs.md diff --git a/products/queries/get-started.md b/products/queries/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/guides/.pages b/products/queries/guides/.pages new file mode 100644 index 000000000..30fd27cb3 --- /dev/null +++ b/products/queries/guides/.pages @@ -0,0 +1,7 @@ +title: Guides +nav: +- 'Construct a Query': construct-a-query.md +- 'Mock a Query': mock-a-query.md +- 'Make a Query Request': query-request.md +- 'Verify a Query Response': verify-response.md +- 'Submit a Query Response': submit-a-query-response.md diff --git a/products/queries/guides/construct-a-query.md b/products/queries/guides/construct-a-query.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/guides/construct-a-query.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/guides/mock-a-query.md b/products/queries/guides/mock-a-query.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/guides/mock-a-query.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/guides/query-request.md b/products/queries/guides/query-request.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/guides/query-request.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/ntt/index.md b/products/queries/guides/submit-response.md similarity index 100% rename from ntt/index.md rename to products/queries/guides/submit-response.md diff --git a/products/queries/guides/verify-response.md b/products/queries/guides/verify-response.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/guides/verify-response.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/overview.md b/products/queries/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/reference/.pages b/products/queries/reference/.pages new file mode 100644 index 000000000..7c1f6fff1 --- /dev/null +++ b/products/queries/reference/.pages @@ -0,0 +1,4 @@ +title: Reference +nav: +- 'Supported Networks': supported-networks.md +- 'Supported Methods': supported-methods.md \ No newline at end of file diff --git a/products/queries/reference/supported-methods.md b/products/queries/reference/supported-methods.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/reference/supported-methods.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/reference/supported-networks.md b/products/queries/reference/supported-networks.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/queries/reference/supported-networks.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/reference/.pages b/products/reference/.pages new file mode 100644 index 000000000..a17e39d11 --- /dev/null +++ b/products/reference/.pages @@ -0,0 +1,8 @@ +title: Reference +nav: +- 'Chain IDs': chain-ids.md +- 'Contract Addresses': contract-addresses.md +- 'Wormhole Finality': consistency-levels.md +- 'Wormhole-Formatted Addresses': wormhole-formatted-addresses.md +- 'Supported Networks': supported-networks.md +- 'Testnet Faucets': testnet-faucets.md diff --git a/build/reference/chain-ids.md b/products/reference/chain-ids.md similarity index 91% rename from build/reference/chain-ids.md rename to products/reference/chain-ids.md index d143f4404..7299bafc4 100644 --- a/build/reference/chain-ids.md +++ b/products/reference/chain-ids.md @@ -11,4 +11,4 @@ The following table documents the chain IDs used by Wormhole and places them alo !!! note Please note, Wormhole chain IDs are different than the more commonly referenced EVM [chain IDs](https://eips.ethereum.org/EIPS/eip-155){target=\_blank}, specified in the Mainnet and Testnet ID columns. ---8<-- 'text/build/reference/chain-ids/chain-ids.md' +--8<-- 'text/products/reference/chain-ids/chain-ids.md' diff --git a/build/reference/consistency-levels.md b/products/reference/consistency-levels.md similarity index 91% rename from build/reference/consistency-levels.md rename to products/reference/consistency-levels.md index 7ffa65ce8..ea6bc3c67 100644 --- a/build/reference/consistency-levels.md +++ b/products/reference/consistency-levels.md @@ -8,4 +8,4 @@ categories: Reference The following table documents each chain's `consistencyLevel` values (i.e., finality reached before signing). The consistency level defines how long the Guardians should wait before signing a VAA. The finalization time depends on the specific chain's consensus mechanism. The consistency level is a `u8`, so any single byte may be used. However, a small subset has particular meanings. If the `consistencyLevel` isn't one of those specific values, the `Otherwise` column describes how it's interpreted. ---8<-- 'text/build/reference/consistency-levels/consistency-levels.md' +--8<-- 'text/products/reference/consistency-levels/consistency-levels.md' diff --git a/build/reference/contract-addresses.md b/products/reference/contract-addresses.md similarity index 68% rename from build/reference/contract-addresses.md rename to products/reference/contract-addresses.md index 7bf87c538..f1566561c 100644 --- a/build/reference/contract-addresses.md +++ b/products/reference/contract-addresses.md @@ -8,23 +8,23 @@ categories: Reference ## Core Contracts ---8<-- 'text/build/reference/contract-addresses/core-contracts.md' +--8<-- 'text/products/reference/contract-addresses/core-contracts.md' ## Token Bridge ---8<-- 'text/build/reference/contract-addresses/token-bridge.md' +--8<-- 'text/products/reference/contract-addresses/token-bridge.md' ## Wormhole Relayer ---8<-- 'text/build/reference/contract-addresses/relayer.md' +--8<-- 'text/products/reference/contract-addresses/relayer.md' ## CCTP ---8<-- 'text/build/reference/contract-addresses/cctp.md' +--8<-- 'text/products/reference/contract-addresses/cctp.md' ## Read-Only Deployments ---8<-- 'text/build/reference/contract-addresses/read-only.md' +--8<-- 'text/products/reference/contract-addresses/read-only.md' !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. diff --git a/build/start-building/supported-networks.md b/products/reference/supported-networks.md similarity index 100% rename from build/start-building/supported-networks.md rename to products/reference/supported-networks.md diff --git a/build/start-building/testnet-faucets.md b/products/reference/testnet-faucets.md similarity index 87% rename from build/start-building/testnet-faucets.md rename to products/reference/testnet-faucets.md index 9dd8dee01..b761f5817 100644 --- a/build/start-building/testnet-faucets.md +++ b/products/reference/testnet-faucets.md @@ -10,4 +10,4 @@ categories: Reference Don't let the need for testnet tokens get in the way of buildling your next great idea with Wormhole. Use this guide to quickly locate the testnet token faucets you need to deploy and test applications and contracts on Wormhole's supported networks. ---8<-- 'text/build/start-building/testnet-faucets/testnet-faucets.md' +--8<-- 'text/products/reference/testnet-faucets/testnet-faucets.md' diff --git a/build/reference/wormhole-formatted-addresses.md b/products/reference/wormhole-formatted-addresses.md similarity index 98% rename from build/reference/wormhole-formatted-addresses.md rename to products/reference/wormhole-formatted-addresses.md index dfc30b607..a7a79639a 100644 --- a/build/reference/wormhole-formatted-addresses.md +++ b/products/reference/wormhole-formatted-addresses.md @@ -92,13 +92,13 @@ Example conversions for EVM and Solana: === "EVM" ```typescript - --8<-- 'code/build/reference/formatted-addresses/evm.ts' + --8<-- 'code/products/reference/formatted-addresses/evm.ts' ``` === "Solana" ```typescript - --8<-- 'code/build/reference/formatted-addresses/solana.ts' + --8<-- 'code/products/reference/formatted-addresses/solana.ts' ``` The result is a standardized address format that is ready for cross-chain operations. diff --git a/products/settlement/.pages b/products/settlement/.pages new file mode 100644 index 000000000..b5c7e2d07 --- /dev/null +++ b/products/settlement/.pages @@ -0,0 +1,7 @@ +title: Settlement +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- concepts +- 'FAQs': faqs.md diff --git a/products/settlement/concepts/.pages b/products/settlement/concepts/.pages new file mode 100644 index 000000000..9ef6dde62 --- /dev/null +++ b/products/settlement/concepts/.pages @@ -0,0 +1,3 @@ +title: Concepts +nav: +- 'Architecture': architecture.md \ No newline at end of file diff --git a/learn/transfers/settlement/architecture.md b/products/settlement/concepts/architecture.md similarity index 96% rename from learn/transfers/settlement/architecture.md rename to products/settlement/concepts/architecture.md index 69429f525..77291f3c6 100644 --- a/learn/transfers/settlement/architecture.md +++ b/products/settlement/concepts/architecture.md @@ -20,7 +20,7 @@ Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster- Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/learn/transfers/settlement/architecture/architecture-1.webp) +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. @@ -62,7 +62,7 @@ First, they lack a competitive price discovery mechanism as limit order prices a Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -![Mayan Swift - Intent-centric design](/docs/images/learn/transfers/settlement/architecture/architecture-2.webp) +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) ### Protocol Flow: How It Works @@ -81,7 +81,7 @@ Mayan Swift addresses these limitations by implementing competitive on-chain Eng Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -![Mayan MCTP diagram](/docs/images/learn/transfers/settlement/architecture/architecture-3.webp) +![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) ### Protocol Flow: How It Works @@ -92,12 +92,12 @@ Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} 3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/build/transfers/settlement/liquidity-layer/){target=\_blank} guide +- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial diff --git a/build/transfers/settlement/faqs.md b/products/settlement/faqs.md similarity index 100% rename from build/transfers/settlement/faqs.md rename to products/settlement/faqs.md diff --git a/products/settlement/get-started.md b/products/settlement/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/settlement/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/settlement/guides/.pages b/products/settlement/guides/.pages new file mode 100644 index 000000000..96019210a --- /dev/null +++ b/products/settlement/guides/.pages @@ -0,0 +1,4 @@ +title: Guides +nav: +- 'Build on the Liquidity Layer': 'liquidity-layer.md' +- 'Run a Solver': 'run-a-solver.md' diff --git a/build/transfers/settlement/liquidity-layer.md b/products/settlement/guides/liquidity-layer.md similarity index 95% rename from build/transfers/settlement/liquidity-layer.md rename to products/settlement/guides/liquidity-layer.md index 9eff2198c..6029a09ca 100644 --- a/build/transfers/settlement/liquidity-layer.md +++ b/products/settlement/guides/liquidity-layer.md @@ -19,7 +19,7 @@ The EVM Token Router is a simple interface against which to integrate. For an in The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` ```solidity title="`placeFastMarketOrder` Interface" ---8<-- 'code/build/transfers/settlement/placeFastMarketOrder.sol' +--8<-- 'code/products/settlement/guides/liquidity-layer/placeFastMarketOrder.sol' ``` ??? interface "Parameters `placeFastMarketOrder()`" @@ -65,7 +65,7 @@ The `placeFastMarketOrder` function returns a sequence number for the Wormhole F The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. ```solidity title="`placeMarketOrder` Interface" ---8<-- 'code/build/transfers/settlement/placeMarketOrder.sol' +--8<-- 'code/products/settlement/guides/liquidity-layer/placeMarketOrder.sol' ``` ??? interface "Parameters `placeMarketOrder()`" diff --git a/build/transfers/settlement/solver.md b/products/settlement/guides/solver.md similarity index 99% rename from build/transfers/settlement/solver.md rename to products/settlement/guides/solver.md index ceaf90048..690080510 100644 --- a/build/transfers/settlement/solver.md +++ b/products/settlement/guides/solver.md @@ -64,7 +64,7 @@ make dependencies The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. ```json title="config.json" ---8<-- 'code/build/transfers/settlement/solver-config.json' +--8<-- 'code/products/settlement/guides/solver/solver-config.json' ``` The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. diff --git a/products/settlement/overview.md b/products/settlement/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/settlement/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/tutorials/settlement/.settlement-routes.md b/products/settlement/tutorials/.settlement-routes.md similarity index 98% rename from tutorials/settlement/.settlement-routes.md rename to products/settlement/tutorials/.settlement-routes.md index 9a0fd7fa3..e1d6ec2b4 100644 --- a/tutorials/settlement/.settlement-routes.md +++ b/products/settlement/tutorials/.settlement-routes.md @@ -31,7 +31,7 @@ Before beginning this project, make sure you have the following: - **Data for parameters** - you will need: - - [Chain IDs](/docs/build/reference/chain-ids/){target=\_blank} for the source and destination chains + - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - An contract address for the token you want to swap and the token you want to receive on the destination chain ## Configure and Setup diff --git a/products/token-bridge/.pages b/products/token-bridge/.pages new file mode 100644 index 000000000..b23d0a9a8 --- /dev/null +++ b/products/token-bridge/.pages @@ -0,0 +1,9 @@ +title: Token Bridge +nav: +- 'Overview': overview.md +- 'Get Started': get-started.md +- guides +- tutorials +- concepts +- 'FAQs': faqs.md +- 'Portal Bridge': https://portalbridge.com/ diff --git a/products/token-bridge/concepts/.pages b/products/token-bridge/concepts/.pages new file mode 100644 index 000000000..255e2cdf0 --- /dev/null +++ b/products/token-bridge/concepts/.pages @@ -0,0 +1,4 @@ +title: Concepts +nav: +- 'Flow of a Transfer': transfer-flow.md +- 'Payload Structure': payload-structure.md diff --git a/products/token-bridge/concepts/payload-structure.md b/products/token-bridge/concepts/payload-structure.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/token-bridge/concepts/payload-structure.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/token-bridge/concepts/transfer-flow.md b/products/token-bridge/concepts/transfer-flow.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/token-bridge/concepts/transfer-flow.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/token-bridge/faqs.md b/products/token-bridge/faqs.md new file mode 100644 index 000000000..d860914f8 --- /dev/null +++ b/products/token-bridge/faqs.md @@ -0,0 +1,36 @@ +--- +title: Token Bridge FAQs +description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +categories: Token-Bridge, Transfer +--- + +## FAQs + +### Can ownership of wrapped tokens be transferred from the Token Bridge? + +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. + + - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself + - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge + +The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. + +Relevant contracts: + + - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} + - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} + - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} + +### How do I update the metadata of a wrapped token? + +Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. + +### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? + +You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. + +### How can I update my wrapped token image on Solscan? + +Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. + +To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. diff --git a/products/token-bridge/get-started.md b/products/token-bridge/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/token-bridge/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/token-bridge/guides/.pages b/products/token-bridge/guides/.pages new file mode 100644 index 000000000..adacb8b94 --- /dev/null +++ b/products/token-bridge/guides/.pages @@ -0,0 +1,3 @@ +title: Guides +nav: +- 'Transfer Wrapped Assets': transfer-wrapped-assets.md diff --git a/products/token-bridge/guides/transfer-wrapped-assets.md b/products/token-bridge/guides/transfer-wrapped-assets.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/token-bridge/guides/transfer-wrapped-assets.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/token-bridge/overview.md b/products/token-bridge/overview.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/products/token-bridge/overview.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/token-bridge/tutorials/.pages b/products/token-bridge/tutorials/.pages new file mode 100644 index 000000000..cce40e0be --- /dev/null +++ b/products/token-bridge/tutorials/.pages @@ -0,0 +1,4 @@ +title: Tutorials +nav: +- 'Complete Token Transfer Workflow': transfer-workflow.md +- 'Create Multichain Tokens': multichain-token.md \ No newline at end of file diff --git a/tutorials/multichain-assets/multichain-token.md b/products/token-bridge/tutorials/multichain-token.md similarity index 90% rename from tutorials/multichain-assets/multichain-token.md rename to products/token-bridge/tutorials/multichain-token.md index f94710797..3efdb309e 100644 --- a/tutorials/multichain-assets/multichain-token.md +++ b/products/token-bridge/tutorials/multichain-token.md @@ -29,7 +29,7 @@ The first step in creating a multichain token is registering your token on its s 4. Locate the **Asset** field and paste the token contract address 5. Click **Next** to proceed -![Source Chain Registration Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-1.webp) +![Source Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp) ## Register the Token on the Target Chain @@ -39,7 +39,7 @@ After registering your token on the source chain, the next step is to select the 2. Connect your wallet to the target chain 3. Click **Next** to finalize the registration process -![Target Chain Registration Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-2.webp) +![Target Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp) ## Send an Attestation Attestation is a key step in the process. It verifies your token’s metadata, ensuring it is correctly recognized on the target chain’s blockchain explorer (e.g., [Etherscan](https://etherscan.io/){target=\_blank}). @@ -47,7 +47,7 @@ Attestation is a key step in the process. It verifies your token’s metadata, e 1. Click **Attest** to initiate the attestation process 2. Approve the transaction in your wallet when prompted -![Send Attestation Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-3.webp) +![Send Attestation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp) !!! note - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token @@ -60,11 +60,11 @@ The final step is to create the wrapped token on the target chain. This token re 1. Click **Create** to generate the wrapped token 2. Approve the transaction in your wallet when prompted -![Create Wrapped Token Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-4.webp) +![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: -![Confirmation Screen](/docs/images/tutorials/multichain-assets/multichain-tokens/multichain-token-5.webp) +![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) ## Additional Steps and Recommendations diff --git a/tutorials/typescript-sdk/tokens-via-token-bridge.md b/products/token-bridge/tutorials/transfer-workflow.md similarity index 84% rename from tutorials/typescript-sdk/tokens-via-token-bridge.md rename to products/token-bridge/tutorials/transfer-workflow.md index e5feadaed..bc74bb4c0 100644 --- a/tutorials/typescript-sdk/tokens-via-token-bridge.md +++ b/products/token-bridge/tutorials/transfer-workflow.md @@ -3,7 +3,7 @@ title: Transfer Tokens via Token Bridge Tutorial description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains --- -# Transfer Tokens via the Token Bridge +# Complete Token Transfer Workflow :simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} @@ -82,7 +82,7 @@ In this section, we’ll guide you through initializing the project, installing 2. Open the `helpers.ts` file and add the following code ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-1.ts" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-1.ts" ``` - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file @@ -107,13 +107,13 @@ In this section, you'll create a script that automates this process by checking 2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:1:6" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:1:6" ``` 3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:8:9" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:8:9" ``` !!! note @@ -122,58 +122,58 @@ In this section, you'll create a script that automates this process by checking 4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:12:15" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:12:15" ``` 5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:18:18" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:18:18" ``` 6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:19:31" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:19:31" ``` - If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/#token-transfers). Otherwise, an attestation must be generated. + If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. 7. **Set up the source chain signer** - the signer creates and submits the attestation transaction ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:34:34" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:34:34" ``` 8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:37:46" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:37:46" ``` 9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:49:58" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:49:58" ``` 10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:65:70" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:65:70" ``` 11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts:74:88" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts:74:88" ``` If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. ??? code "Complete script" ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-2.ts" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-2.ts" ``` ### Run the Wrapped Token Creation @@ -203,43 +203,43 @@ Before initiating a cross-chain transfer, you must set up the chain context and 2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:1:14" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:1:14" ``` 3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:15:16" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:15:16" ``` 4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:19:20" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:19:20" ``` 5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:23:24" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:23:24" ``` 6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:27:27" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:27:27" ``` 7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:30:30" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:30:30" ``` 8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:33:33" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:33:33" ``` !!! note @@ -248,19 +248,19 @@ Before initiating a cross-chain transfer, you must set up the chain context and 9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:36:36" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:36:36" ``` 10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:39:45" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:39:45" ``` Finally, we use `process.exit(0);` to close the script once the transfer completes ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:47:48" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:47:48" ``` ### Token Transfer Logic @@ -272,8 +272,8 @@ This section defines the `tokenTransfer` function, which manages the core steps The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. ```typescript ---8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:50:61" ---8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:96" +--8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:50:61" +--8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:96" ``` #### Steps to Transfer Tokens @@ -283,19 +283,19 @@ The `tokenTransfer` function consists of several key steps to facilitate the cro 1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:63:70" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:63:70" ``` 2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:72:80" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:72:80" ``` 3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:84:85" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:84:85" ``` - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} @@ -313,18 +313,18 @@ The `tokenTransfer` function consists of several key steps to facilitate the cro 4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:90:90" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:90:90" ``` 5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts:94:95" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts:94:95" ``` ??? code "Complete script" ```typescript - --8<-- "code/tutorials/typescript-sdk/tokens-via-token-bridge/token-bridge-3.ts" + --8<-- "code/products/token-bridge/tutorials/transfer-workflow/token-bridge-3.ts" ``` ### Run the Native Token Transfer diff --git a/protocol/.pages b/protocol/.pages new file mode 100644 index 000000000..dda752bd4 --- /dev/null +++ b/protocol/.pages @@ -0,0 +1,7 @@ +title: Protocol +nav: +- 'Introduction to Wormhole': introduction.md +- 'Architecture Overview': architecture.md +- 'Security Overview': security.md +- infrastructure +- infrastructure-guides diff --git a/learn/infrastructure/architecture.md b/protocol/architecture.md similarity index 66% rename from learn/infrastructure/architecture.md rename to protocol/architecture.md index 1c775843e..f077fefee 100644 --- a/learn/infrastructure/architecture.md +++ b/protocol/architecture.md @@ -10,12 +10,12 @@ categories: Basics Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/learn/infrastructure/architecture/architecture-1.webp) +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} 3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain 4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. @@ -27,17 +27,17 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components - **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract ## Off-Chain Components - **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/learn/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/learn/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution - **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/learn/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/learn/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers @@ -51,7 +51,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - :octicons-tools-16:{ .lg .middle } **Core Messaging** @@ -59,6 +59,6 @@ The preceding diagram outlines the end-to-end flow of multichain communication t Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) diff --git a/protocol/infrastructure-guides/.pages b/protocol/infrastructure-guides/.pages new file mode 100644 index 000000000..c2835f26a --- /dev/null +++ b/protocol/infrastructure-guides/.pages @@ -0,0 +1,4 @@ +title: Infrastructure Guides +nav: +- 'Run a Custom Relayer': run-relayer.md +- 'Run a Spy': run-spy.md diff --git a/build/infrastructure/relayers/run-relayer.md b/protocol/infrastructure-guides/run-relayer.md similarity index 92% rename from build/infrastructure/relayers/run-relayer.md rename to protocol/infrastructure-guides/run-relayer.md index 280eb2a9e..45034a0ff 100644 --- a/build/infrastructure/relayers/run-relayer.md +++ b/protocol/infrastructure-guides/run-relayer.md @@ -21,7 +21,7 @@ This guide teaches you how to set up and configure a custom relayer for efficien To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs.
- ![Custom relayer](/docs/images/build/infrastructure/relayers/run-relayer/relayer-1.webp) + ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp)
The off-chain components outlined in blue must be implemented.
@@ -62,13 +62,13 @@ In the following example, you'll: 3. Start the relayer app ```typescript ---8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-1.ts' +--8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-1.ts' ``` The first meaningful line instantiates the `StandardRelayerApp`, a subclass of the `RelayerApp` with standard defaults. ```typescript ---8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-2.ts' +--8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-2.ts' ``` The only field you pass in the `StandardRelayerAppOpts` is the name to help identify log messages and reserve a namespace in Redis. @@ -78,7 +78,7 @@ The only field you pass in the `StandardRelayerAppOpts` is the name to help iden Other options can be passed to the `StandardRelayerApp` constructor to configure the app further. ```typescript - --8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-3.ts' + --8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-3.ts' ``` The next meaningful line in the example adds a filter middleware component. This middleware will cause the relayer app to request a subscription from the Spy for any VAAs that match the criteria and invoke the callback with the VAA. @@ -86,7 +86,7 @@ The next meaningful line in the example adds a filter middleware component. This If you'd like your program to subscribe to `multiple` chains and addresses, you can call the same method several times or use the `multiple` helper. ```typescript ---8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-4.ts' +--8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-4.ts' ``` The last line in the simple example runs `await app.listen()`, which starts the relayer engine. Once started, the Relayer Engine issues subscription requests to the Spy and begins any other workflows (e.g., tracking missed VAAs). @@ -102,7 +102,7 @@ The source code for this example is available in the [`relayer-engine` repositor Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. -More details about the Spy are available in the [Spy Documentation](/docs/learn/infrastructure/spy){target=\_blank}. +More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. ### Wormhole Network Spy @@ -153,7 +153,7 @@ docker run --rm -p 6379:6379 --name redis-docker -d redis You can also use the Wormhole SDK to poll the Guardian RPC until a signed VAA is ready using the SDK's `getSignedVAAWithRetry` function. ```ts ---8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-5.ts' +--8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-5.ts' ``` Once you have the VAA, the delivery method is chain-dependent. @@ -163,7 +163,7 @@ Once you have the VAA, the delivery method is chain-dependent. On EVM chains, the bytes for the VAA can be passed directly as an argument to an ABI method. ```ts - --8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-6.ts' + --8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-6.ts' ``` === "Solana" @@ -171,5 +171,5 @@ Once you have the VAA, the delivery method is chain-dependent. On Solana, the VAA is first posted to the core bridge, and then a custom transaction is prepared to process and validate the VAA. ```ts - --8<-- 'code/build/infrastructure/relayers/run-relayer/snippet-7.ts' + --8<-- 'code/protocol/infrastructure-guides/run-relayer/snippet-7.ts' ``` diff --git a/build/infrastructure/spy/run-spy.md b/protocol/infrastructure-guides/run-spy.md similarity index 98% rename from build/infrastructure/spy/run-spy.md rename to protocol/infrastructure-guides/run-spy.md index 61fcb6bef..3ddc75068 100644 --- a/build/infrastructure/spy/run-spy.md +++ b/protocol/infrastructure-guides/run-spy.md @@ -9,7 +9,7 @@ description: Learn how to run a Spy locally to listen for and forward messages ( The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. -For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/learn/infrastructure/spy/){target=\_blank}. +For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. ## How to Start a Spy diff --git a/protocol/infrastructure/.pages b/protocol/infrastructure/.pages new file mode 100644 index 000000000..daf5eef6b --- /dev/null +++ b/protocol/infrastructure/.pages @@ -0,0 +1,7 @@ +title: Infrastructure Components +nav: +- 'Core Contracts': 'core-contracts.md' +- 'VAAs': 'vaas.md' +- 'Guardians': 'guardians.md' +- 'Spy': 'spy.md' +- 'Relayers': 'relayer.md' diff --git a/learn/infrastructure/core-contracts.md b/protocol/infrastructure/core-contracts.md similarity index 89% rename from learn/infrastructure/core-contracts.md rename to protocol/infrastructure/core-contracts.md index 11d6a461c..84c4091c7 100644 --- a/learn/infrastructure/core-contracts.md +++ b/protocol/infrastructure/core-contracts.md @@ -31,7 +31,7 @@ The following describes the role of the Wormhole Core Contract in message transf 2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/learn/infrastructure/architecture/) page. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. ### Message Submission @@ -39,13 +39,13 @@ You can send multichain messages by calling a function against the source chain - `emitterAddress` - the contract which made the call to publish the message - `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/build/reference/consistency-levels/){target=\_blank} reference page +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. ### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/learn/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. ## Multicast @@ -53,7 +53,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/learn/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -67,7 +67,7 @@ Because the VAA creation is separate from relaying, the multicast model does not Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - [:custom-arrow: Learn About VAAs](/docs/learn/infrastructure/vaas/) + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** @@ -75,6 +75,6 @@ Because the VAA creation is separate from relaying, the multicast model does not This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - [:custom-arrow: Build with Core Contracts](/docs/build/core-messaging/core-contracts/) + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) diff --git a/learn/infrastructure/guardians.md b/protocol/infrastructure/guardians.md similarity index 93% rename from learn/infrastructure/guardians.md rename to protocol/infrastructure/guardians.md index e9f643280..729a5388a 100644 --- a/learn/infrastructure/guardians.md +++ b/protocol/infrastructure/guardians.md @@ -14,7 +14,7 @@ Guardians fulfill their role in the messaging protocol as follows: 2. Guardians combine their indpendent signatures to form a multisig 3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs). +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). ## Guardian Network @@ -54,11 +54,11 @@ This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus ### Modularity -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/learn/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. ### Chain Agnosticism -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/learn/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. ### Scalability @@ -87,7 +87,7 @@ These principles combine to create a clear pathway towards a fully trustless int Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/learn/infrastructure/relayer/) + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - :octicons-tools-16:{ .lg .middle } **Query Guardian Data** diff --git a/learn/infrastructure/relayer.md b/protocol/infrastructure/relayer.md similarity index 92% rename from learn/infrastructure/relayer.md rename to protocol/infrastructure/relayer.md index e9f5a2920..3ae2e6eba 100644 --- a/learn/infrastructure/relayer.md +++ b/protocol/infrastructure/relayer.md @@ -8,7 +8,7 @@ categories: Basics This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. There are three primary types of relayers discussed: @@ -76,7 +76,7 @@ Though simple, this type of relaying is generally not recommended if your aim is Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/learn/infrastructure/spy/). +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). ### Key Features @@ -142,7 +142,7 @@ Developers should note that the choice of relayers depends on their project's sp Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [:custom-arrow: Learn More About the Spy](/docs/learn/infrastructure/spy/) + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** @@ -150,7 +150,7 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [:custom-arrow: Get Started with Wormhole Relayers](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** @@ -158,6 +158,6 @@ Developers should note that the choice of relayers depends on their project's sp Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - [:custom-arrow: Get Started with Custom Relayers](/docs/infrastructure/relayers/run-relayer/) + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) diff --git a/learn/infrastructure/spy.md b/protocol/infrastructure/spy.md similarity index 95% rename from learn/infrastructure/spy.md rename to protocol/infrastructure/spy.md index dbf69f9d1..5add5a7f0 100644 --- a/learn/infrastructure/spy.md +++ b/protocol/infrastructure/spy.md @@ -30,7 +30,7 @@ This monitoring capability is especially beneficial for applications that need i A Spy can access the following categories of messages shared over the gossip protocol: -- [Verifiable Action Approvals (VAAs)](/docs/learn/infrastructure/vaas/){target=\_blank} - packets of multichain data +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification @@ -82,7 +82,7 @@ A Spy can access the following categories of messages shared over the gossip pro Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - [:custom-arrow: Spin Up a Spy](/docs/infrastructure/spy/run-spy/){target=\_blank} + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - :octicons-code-16:{ .lg .middle } **Use Queries** diff --git a/learn/infrastructure/vaas.md b/protocol/infrastructure/vaas.md similarity index 95% rename from learn/infrastructure/vaas.md rename to protocol/infrastructure/vaas.md index 3740f79df..f59317e95 100644 --- a/learn/infrastructure/vaas.md +++ b/protocol/infrastructure/vaas.md @@ -8,7 +8,7 @@ categories: Basics Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -[Guardians](/docs/learn/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. @@ -59,7 +59,7 @@ Guardian watchers are specialized processes that monitor each blockchain in real The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. ```js ---8<-- 'code/learn/infrastructure/VAAs/snippet-1.js' +--8<-- 'code/protocol/infrastructure/VAAs/snippet-1.js' ``` !!!tip "Hash vs. double hash" @@ -159,7 +159,7 @@ Governance messages contain pre-defined actions, which can target the various Wo Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. ```js ---8<-- 'code/learn/infrastructure/VAAs/snippet-2.js' +--8<-- 'code/protocol/infrastructure/VAAs/snippet-2.js' ``` #### Actions @@ -179,7 +179,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess 2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA 3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -![Lifetime of a message diagram](/docs/images/learn/infrastructure/vaas/lifetime-vaa-diagram.webp) +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) ## Next Steps @@ -191,7 +191,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - [:custom-arrow: Learn About Guardians](/docs/learn/infrastructure/guardians/) + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** @@ -199,7 +199,7 @@ With the concepts now defined, it is possible to illustrate a full flow for mess Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - [:custom-arrow: Build with Wormhole Relayer](/docs/build/core-messaging/wormhole-relayers/) + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) diff --git a/learn/introduction.md b/protocol/introduction.md similarity index 87% rename from learn/introduction.md rename to protocol/introduction.md index a0146c34a..1ac24ff46 100644 --- a/learn/introduction.md +++ b/protocol/introduction.md @@ -12,10 +12,10 @@ Wormhole addresses this problem by providing a _generic message-passing_ protoco Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -![Message-passing process in the Wormhole protocol](/docs/images/learn/introduction/introduction-1.webp) +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) !!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/learn/infrastructure/architecture/){target=\_blank}. + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. @@ -37,7 +37,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/build/toolkit/typescript-sdk/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -48,7 +48,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access - **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals - **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum @@ -56,7 +56,7 @@ Consider the following examples of potential applications enabled by Wormhole: Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/learn/infrastructure/architecture/){target=\_blank}** - explore the components of the protocol +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol - **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole ## Demos diff --git a/learn/security.md b/protocol/security.md similarity index 94% rename from learn/security.md rename to protocol/security.md index 8296af2ea..b62d36e06 100644 --- a/learn/security.md +++ b/protocol/security.md @@ -8,7 +8,7 @@ categories: Basics ## Core Security Assumptions -At its core, Wormhole is secured by a network of [Guardian](/docs/learn/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} @@ -73,7 +73,7 @@ Wormhole builds in the open and is always open source. - **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/learn/infrastructure/core-contracts/){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** ## Audits diff --git a/tools/.pages b/tools/.pages new file mode 100644 index 000000000..c83c147f8 --- /dev/null +++ b/tools/.pages @@ -0,0 +1,6 @@ +title: Developer Tooling +nav: +- typescript-sdk +- solidity-sdk +- 'Wormholescan Explorer': https://wormholescan.io/ +- 'Wormholescan API': https://wormholescan.io/#/developers/api-doc \ No newline at end of file diff --git a/tools/solidity-sdk/.pages b/tools/solidity-sdk/.pages new file mode 100644 index 000000000..ca9d522d1 --- /dev/null +++ b/tools/solidity-sdk/.pages @@ -0,0 +1,4 @@ +title: Solidity SDK +nav: +- 'Get Started': get-started.md +- 'SDK Reference': sdk-reference.md \ No newline at end of file diff --git a/tools/solidity-sdk/get-started.md b/tools/solidity-sdk/get-started.md new file mode 100644 index 000000000..30404ce4c --- /dev/null +++ b/tools/solidity-sdk/get-started.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/build/toolkit/solidity-sdk.md b/tools/solidity-sdk/sdk-reference.md similarity index 90% rename from build/toolkit/solidity-sdk.md rename to tools/solidity-sdk/sdk-reference.md index 2f35789ba..880e61e16 100644 --- a/build/toolkit/solidity-sdk.md +++ b/tools/solidity-sdk/sdk-reference.md @@ -53,7 +53,7 @@ The Wormhole Solidity SDK consists of key components that streamline cross-chain The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication. -You can refer to the [Wormhole relayer documentation](/docs/build/core-messaging/wormhole-relayers/){target=\_blank} for more details. +You can refer to the [Wormhole relayer documentation](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} for more details. Key modules in the SDK include: @@ -71,7 +71,7 @@ Please refer to the complete `WormholeRelayerSDK.sol` file below for further det ???- code "`WormholeRelayerSDK.sol`" ```solidity - --8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-1.sol" + --8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol" ``` ### Base Contract Overview @@ -81,27 +81,27 @@ The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/bl - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions ```solidity - --8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol:22:28" + --8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:22:28" ``` - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources ```solidity - --8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol:45:54" + --8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:45:54" ``` These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. ???- code "`Base.sol`" ```solidity - --8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-2.sol" + --8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol" ``` ### Interface for Cross-Chain Messages The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. -For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/build/core-messaging/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: +For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: - **`IWormholeRelayer`** – methods for sending cross-chain messages, VAAs, and token transfers - **`IWormholeReceiver`** – the required implementation for receiving cross-chain messages @@ -129,7 +129,7 @@ This section covers cross-chain messaging and token transfers and shows how to u To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: ```solidity ---8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-3.sol" +--8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol" ``` This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. @@ -139,7 +139,7 @@ This contract extends `Base.sol` and allows sending cross-chain messages securel The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. ```solidity ---8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-4.sol" +--8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol" ``` In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. @@ -149,13 +149,13 @@ In this example, `TokenSender` initiates a token transfer to another chain. The To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. ```solidity ---8<-- "code/build/toolkit/solidity-sdk/solidity-sdk-5.sol" +--8<-- "code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol" ``` In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. !!! note - Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/build/core-messaging/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. + Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/products/messaging/guides/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. ## Testing Environment @@ -163,5 +163,5 @@ The SDK includes built-in support for Forge-based testing, which allows you to t For a detailed example, check out the below repositories: - - [Cross chain messaging](/docs/tutorials/solidity-sdk/cross-chain-contracts/){target=\_blank} - - [Cross chain token transfer](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/){target=\_blank} \ No newline at end of file + - [Cross chain messaging](/docs/products/messaging/tutorials/cross-chain-contracts/){target=\_blank} + - [Cross chain token transfer](/docs/products/messaging/tutorials/cross-chain-token-contracts/){target=\_blank} \ No newline at end of file diff --git a/tools/typescript-sdk/.pages b/tools/typescript-sdk/.pages new file mode 100644 index 000000000..099f614be --- /dev/null +++ b/tools/typescript-sdk/.pages @@ -0,0 +1,5 @@ +title: TypeScript SDK +nav: +- 'Get Started': get-started.md +- 'SDK Reference': sdk-reference.md +- guides diff --git a/tools/typescript-sdk/get-started.md b/tools/typescript-sdk/get-started.md new file mode 100644 index 000000000..e69de29bb diff --git a/build/toolkit/typescript-sdk/.pages b/tools/typescript-sdk/guides/.pages similarity index 67% rename from build/toolkit/typescript-sdk/.pages rename to tools/typescript-sdk/guides/.pages index c3b4d3669..3f4d6ed1f 100644 --- a/build/toolkit/typescript-sdk/.pages +++ b/tools/typescript-sdk/guides/.pages @@ -1,7 +1,5 @@ -title: TypeScript SDK +title: Guides nav: - - index.md - - 'TypeScript SDK' : 'wormhole-sdk.md' - 'Data Layouts': 'sdk-layout.md' - 'Building Protocols and Payloads': 'protocols-payloads.md' - 'VAAs and Protocol Messages': 'vaas-protocols.md' \ No newline at end of file diff --git a/build/toolkit/typescript-sdk/protocols-payloads.md b/tools/typescript-sdk/guides/protocols-payloads.md similarity index 95% rename from build/toolkit/typescript-sdk/protocols-payloads.md rename to tools/typescript-sdk/guides/protocols-payloads.md index 6a61f0949..9fb10d607 100644 --- a/build/toolkit/typescript-sdk/protocols-payloads.md +++ b/tools/typescript-sdk/guides/protocols-payloads.md @@ -69,7 +69,7 @@ Protocol registration involves two key tasks: For example, here's the `TokenBridge` protocol registration: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-1.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-1.ts" ``` This code snippet: @@ -84,7 +84,7 @@ You can view the full implementation in the [`TokenBridge` protocol file](https: Some protocols require platform-specific behavior. For instance, the EVM-compatible Wormhole Registry maps native addresses for Ethereum-based chains: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-2.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-2.ts" ``` This ensures that `EvmAddress` is registered as the native address type for EVM-compatible platforms. See the [EVM platform address file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/platforms/evm/src/address.ts#L98-L106){target=\_blank} for details. @@ -108,7 +108,7 @@ Payload registration involves: 1. **Define payload layouts** - create layouts to structure your payloads. For instance, a protocol might use a `TransferWithPayload` layout: ```typescript - --8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-3.ts" + --8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-3.ts" ``` 2. **Register payloads** - use `registerPayloadTypes` to map payload literals to their layouts: @@ -130,7 +130,7 @@ These steps link payload literals and their layouts, enabling seamless runtime h At the core of the payload registration process is the `payloadFactory`, a registry that manages the mapping between payload literals and layouts: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-4.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-4.ts" ``` - The `payloadFactory` ensures each payload literal maps to its layout uniquely @@ -140,7 +140,7 @@ This implementation ensures dynamic, efficient handling of payloads at runtime. ## Integrate Protocols with Payloads -Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank}. +Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}. ### Payload Discriminators @@ -158,7 +158,7 @@ This system ensures: Below is an example of how the Wormhole SDK builds a discriminator to distinguish between payload layouts: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-5.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-5.ts" ``` - [`layoutDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/9105de290c91babbf8ad031bd89cc75ee38739c8/core/base/src/utils/layout.ts#L16){target=\_blank} takes a list of layouts and generates a function that can identify the appropriate layout for a given serialized payload @@ -180,7 +180,7 @@ Payloads are registered to the `TokenBridge` protocol via the `PayloadLiteralToL Additionally, the protocol uses reusable layouts like [`transferCommonLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L29C7-L47){target=\_blank} and extends them in more specialized layouts such as [`transferWithPayloadLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L49-L57){target=\_blank}: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-6.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-6.ts" ``` This layout includes: @@ -194,7 +194,7 @@ This layout includes: To manage multiple payloads, the `TokenBridge` protocol utilizes a discriminator to distinguish between payload types dynamically. For example: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-7.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-7.ts" ``` - The [`getTransferDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L67-L70){target=\_blank} function dynamically evaluates payloads using predefined layouts @@ -205,7 +205,7 @@ To manage multiple payloads, the `TokenBridge` protocol utilizes a discriminator Here’s how the `TokenBridge` protocol connects its payloads to the Wormhole SDK: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/protocols-payloads/pl-8.ts" +--8<-- "code/tools/typescript-sdk/guides/protocols-payloads/pl-8.ts" ``` This registration links the `TokenBridge` payload literals to their respective layouts, enabling serialization and deserialization at runtime. diff --git a/build/toolkit/typescript-sdk/sdk-layout.md b/tools/typescript-sdk/guides/sdk-layout.md similarity index 92% rename from build/toolkit/typescript-sdk/sdk-layout.md rename to tools/typescript-sdk/guides/sdk-layout.md index 854ef8699..7d3a6cd90 100644 --- a/build/toolkit/typescript-sdk/sdk-layout.md +++ b/tools/typescript-sdk/guides/sdk-layout.md @@ -38,7 +38,7 @@ Layout items can represent: Below is an example of a layout that might be used to serialize a message across the Wormhole protocol: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-0.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-0.ts" ``` In this example: @@ -73,7 +73,7 @@ Layouts also allow for custom conversions, which help map complex or custom type For example, consider a custom conversion for a chain ID: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-1.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-1.ts" ``` This setup allows Wormhole to convert between human-readable formats and binary-encoded data used in payloads. @@ -83,7 +83,7 @@ This setup allows Wormhole to convert between human-readable formats and binary- The layout system performs error checks during serialization and deserialization. An error is thrown if data is incorrectly sized or in the wrong format. Refer to the below example: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-2.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-2.ts" ``` ## Application of Layouts @@ -97,7 +97,7 @@ To get started with layouts in Wormhole, you need to define your structure. A la Consider the following layout for a payload: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-3.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-3.ts" ``` In this example: @@ -112,7 +112,7 @@ In this example: Once a layout is defined, the next step is to serialize data according to that structure. You can accomplish this using the `serializeLayout` function from the Wormhole SDK. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-4.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-4.ts" ``` This takes the data structure (`examplePayload`) and serializes it according to the rules defined in the layout (`exampleLayout`). The result is a `Uint8Array` representing the serialized binary data. @@ -122,7 +122,7 @@ This takes the data structure (`examplePayload`) and serializes it according to Deserialization is the reverse of serialization. Given a serialized `Uint8Array`, we can convert it back into its original structure using the `deserializeLayout` function. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-5.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-5.ts" ``` This will output the structured object, making it easy to work with data transmitted or received from another chain. @@ -150,7 +150,7 @@ In complex protocols, layouts can contain nested structures. Nested layouts beco Refer to the following nested layout where a message contains nested fields: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-6.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-6.ts" ``` In this layout: @@ -171,7 +171,7 @@ type NestedMessage = LayoutToType; This ensures that when you serialize or deserialize data, it matches the expected structure. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-7.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-7.ts" ``` Attempting to assign data of incorrect types will result in a compile-time error. The Wormhole SDK's layout system enforces strong types, reducing runtime errors and improving code reliability. @@ -181,7 +181,7 @@ Attempting to assign data of incorrect types will result in a compile-time error You can serialize and deserialize nested structures in the same way as simpler layouts: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-8.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-8.ts" ``` Strong typing in TypeScript ensures that the message object conforms to the nested layout structure. This reduces the risk of data inconsistency during cross-chain communication. @@ -207,7 +207,7 @@ const chainItemBase = { binary: 'uint', size: 2 } as const; The dynamic chain ID layout, [`chainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L13-L40){target=\_blank}, extends `chainItemBase` by adding flexible custom conversion logic. It enables runtime validation of chain IDs, supports optional null values, and restricts chain IDs to a predefined set when needed. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-9.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-9.ts" ``` This layout is versatile. It allows the serialization of human-readable chain names (e.g., `Ethereum`) to numeric IDs (e.g., `1`) and vice versa. This is particularly useful when working with dynamic configurations or protocols supporting multiple chains. @@ -217,7 +217,7 @@ This layout is versatile. It allows the serialization of human-readable chain na The fixed chain ID layout, [`fixedChainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L42-L49){target=\_blank}, is more rigid. It also extends `chainItemBase`, but the custom field is hardcoded for a single chain. This eliminates runtime validation and enforces strict adherence to a specific chain. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-10.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-10.ts" ``` This layout allows developers to efficiently serialize and deserialize messages involving a single, fixed chain ID. @@ -231,7 +231,7 @@ The Wormhole SDK uses a Universal Address Layout to serialize and deserialize bl The [`universalAddressItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/universalAddress.ts#L7-L14){target=\_blank} defines the layout for addresses. It uses the binary type bytes and enforces a fixed size of 32 bytes for consistency. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-11.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-11.ts" ``` This layout ensures consistent address handling by defining the following: @@ -248,7 +248,7 @@ In the Wormhole SDK, the Signature Layout defines how to serialize and deseriali The `signatureLayout` specifies the binary structure of a secp256k1 signature. It divides the signature into three components: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-12.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-12.ts" ``` This layout provides a clear binary format for the secp256k1 signature, making it efficient to process within the Wormhole protocol. @@ -258,7 +258,7 @@ This layout provides a clear binary format for the secp256k1 signature, making i The [`signatureItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/signature.ts#L15-L22){target=\_blank} builds upon the `signatureLayout` by adding custom conversion logic. This conversion transforms raw binary data into a high-level `Signature` object and vice versa. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-13.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-13.ts" ``` The `custom` field ensures seamless integration of raw binary data with the `Signature` class, encapsulating signature-specific logic. @@ -274,7 +274,7 @@ The Wormhole SDK’s layout system is designed to handle various data structures For example, different message types can be identified using a payload ID, and the layout for each message can be determined at runtime: ```typescript - --8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-14.ts" + --8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-14.ts" ``` The switch statement helps developers parse multiple payload types using the same structure, depending on a control field like an ID. @@ -288,7 +288,7 @@ The Wormhole SDK’s layout system is designed to handle various data structures In some cases, a field may always contain a predefined value. The layout system supports fixed conversions, allowing developers to “hard-code” these values: ```typescript - --8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-15.ts" + --8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-15.ts" ``` **Example: Omitted Fields** @@ -296,7 +296,7 @@ The Wormhole SDK’s layout system is designed to handle various data structures Omitted fields are useful for handling padding or reserved fields that do not carry meaningful information and can safely be excluded from the deserialized output: ```typescript - --8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-16.ts" + --8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-16.ts" ``` In this example, `reserved` is a padding field with a fixed, non-dynamic value that serves no functional purpose. It is omitted from the deserialized result but still considered during serialization to maintain the correct binary format. @@ -316,13 +316,13 @@ VAAs are the backbone of Wormhole’s cross-chain communication. Each VAA is a s The Wormhole SDK organizes the VAA structure into three key components: - [**Header**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L37-L41){target=\_blank} - contains metadata such as the Guardian set index and an array of Guardian signatures - - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} + - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} - **Payload** - provides application-specific data, such as the actual message or operation being performed **Header layout:** ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-17.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-17.ts" ``` The header defines metadata for validating and processing the VAA, such as the Guardian set index and signatures. Each signature is represented using the `signatureItem` layout, ensuring consistency and compatibility across different platforms. @@ -334,7 +334,7 @@ The header defines metadata for validating and processing the VAA, such as the G **Envelope layout:** ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-18.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-18.ts" ``` The envelope encapsulates the VAA's core message data, including chain-specific information like the emitter address and sequence number. This structured layout ensures that the VAA can be securely transmitted across chains. @@ -344,7 +344,7 @@ The envelope encapsulates the VAA's core message data, including chain-specific The Payload contains the user-defined data specific to the application or protocol, such as a token transfer message, governance action, or other cross-chain operation. The layout of the payload is dynamic and depends on the payload type, identified by the `payloadLiteral` field. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-19.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-19.ts" ``` This example demonstrates a payload containing: @@ -369,7 +369,7 @@ At runtime, the payload layout is appended to the `baseLayout` to form the compl The Wormhole SDK provides the [`serialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L48-L54){target=\_blank} function to serialize a VAA message. This function combines the base layout (header and envelope) with the appropriate payload layout, ensuring the message’s format is correct for transmission across chains. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-20.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-20.ts" ``` ???- note "How does it work?" @@ -377,7 +377,7 @@ The Wormhole SDK provides the [`serialize`](https://github.com/wormhole-foundati Internally, the serialize function dynamically combines the `baseLayout` (header and envelope) with the payload layout defined by the `payloadLiteral`. The complete layout is then passed to the `serializeLayout` function, which converts the data into binary format. ```typescript - --8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-21.ts" + --8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-21.ts" ``` #### Deserializing VAA Data @@ -385,7 +385,7 @@ The Wormhole SDK provides the [`serialize`](https://github.com/wormhole-foundati The Wormhole SDK provides the [`deserialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L162-L200){target=\_blank} function to parse a VAA from its binary format back into a structured object. This function uses the `baseLayout` and payload discriminator logic to ensure the VAA is correctly interpreted. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-22.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-22.ts" ``` ???- note "How does it work?" @@ -393,14 +393,14 @@ The Wormhole SDK provides the [`deserialize`](https://github.com/wormhole-founda Internally, the `deserialize` function uses the `baseLayout` (header and envelope) to parse the main VAA structure. It then identifies the appropriate payload layout using the provided payload type or discriminator. ```typescript - --8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-23.ts" + --8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-23.ts" ``` ### Registering Custom Payloads In the Wormhole SDK, payloads rely on layouts to define their binary structure, ensuring consistency and type safety across protocols. Custom payloads extend this functionality, allowing developers to handle protocol-specific features or unique use cases. -To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} page for a detailed guide. +To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} page for a detailed guide. ## Common Pitfalls & Best Practices @@ -441,7 +441,7 @@ Rather than defining sizes or types manually, reuse the predefined layout items For instance, use the `chainItem` layout for chain IDs or `universalAddressItem` for blockchain addresses: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-25.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-25.ts" ``` By leveraging predefined layout items, you reduce redundancy, maintain consistency, and ensure compatibility with Wormhole’s standards. @@ -463,7 +463,7 @@ Focusing on reusing predefined layout items and converting deserialized data int Always handle errors during both serialization and deserialization. Catching exceptions allows you to log or resolve issues gracefully when working with potentially corrupted or invalid data. ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-26.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-26.ts" ``` #### Leverage Reusable Layouts @@ -473,7 +473,7 @@ Creating reusable layouts for commonly repeated structures improves code maintai For example, define a reusable layout for chain IDs and addresses: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/sdk-layout/layout-27.ts" +--8<-- "code/tools/typescript-sdk/guides/sdk-layout/layout-27.ts" ``` By abstracting common elements into a single layout, you ensure consistency across different parts of your application and simplify future updates. diff --git a/build/toolkit/typescript-sdk/vaas-protocols.md b/tools/typescript-sdk/guides/vaas-protocols.md similarity index 83% rename from build/toolkit/typescript-sdk/vaas-protocols.md rename to tools/typescript-sdk/guides/vaas-protocols.md index bbf8ebb81..06892e768 100644 --- a/build/toolkit/typescript-sdk/vaas-protocols.md +++ b/tools/typescript-sdk/guides/vaas-protocols.md @@ -8,12 +8,12 @@ categories: Typescript-SDK ## Introduction -Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/learn/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. +Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. For deeper insights into serialization, deserialization, and protocol design, refer to: -- [Data Layouts](/docs/build/toolkit/typescript-sdk/sdk-layout/){target=\_blank} for serialization concepts -- [Building Protocols and Payloads](/docs/build/toolkit/typescript-sdk/protocols-payloads/){target=\_blank} for designing custom protocol messages +- [Data Layouts](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank} for serialization concepts +- [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} for designing custom protocol messages This guide will help you understand how to handle VAAs and protocol messages in off-chain and on-chain scenarios. @@ -54,10 +54,10 @@ Each protocol integrates its payload format into the VAA structure, ensuring con The TypeScript SDK is designed for off-chain operations like reading, validating, and manipulating VAAs before submitting them to a chain. Developers can easily deserialize VAAs to extract protocol payloads and prepare actions such as initiating token transfers or constructing delivery instructions. -In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank}: +In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank}: ```typescript ---8<-- "code/build/toolkit/typescript-sdk/vaas-protocols/ts-sdk.ts" +--8<-- "code/tools/typescript-sdk/guides/vaas-protocols/ts-sdk.ts" ``` For more details, you can refer to the [parseVAA example](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts){target=\_blank} in the Wormhole SDK repository. @@ -69,5 +69,5 @@ The Solidity SDK enables on-chain processing of VAAs directly within smart contr Below is an example of parsing an envelope on-chain using the Solidity SDK: ```solidity ---8<-- "code/build/toolkit/typescript-sdk/vaas-protocols/solidity-sdk.sol" +--8<-- "code/tools/typescript-sdk/guides/vaas-protocols/solidity-sdk.sol" ``` \ No newline at end of file diff --git a/build/toolkit/typescript-sdk/wormhole-sdk.md b/tools/typescript-sdk/sdk-reference.md similarity index 91% rename from build/toolkit/typescript-sdk/wormhole-sdk.md rename to tools/typescript-sdk/sdk-reference.md index d5f4ed847..63bb1a1ef 100644 --- a/build/toolkit/typescript-sdk/wormhole-sdk.md +++ b/tools/typescript-sdk/sdk-reference.md @@ -97,48 +97,48 @@ Alternatively, you can install a specific set of published packages individually Getting your integration started is simple. First, import Wormhole: ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts::1' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts::1' ``` Then, import each of the ecosystem [platforms](#platforms) that you wish to support: ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts:4:9' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:4:9' ``` To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts:13:20' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:13:20' ``` With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts:22:22' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:22:22' ``` You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts:54:61' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:54:61' ``` ??? code "View the complete script" ```ts - --8<-- 'code/build/toolkit/typescript-sdk/get-vaa.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts' ``` Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/config-override.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/config-override.ts' ``` ??? code "View the complete script" ```ts - --8<-- 'code/build/toolkit/typescript-sdk/config.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/config.ts' ``` ## Concepts @@ -172,7 +172,7 @@ See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-fou The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/get-chain.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-chain.ts' ``` ### Addresses @@ -180,7 +180,7 @@ The `definitions` package of the SDK includes the `ChainContext` class, which cr The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/addresses.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/addresses.ts' ``` ### Tokens @@ -192,7 +192,7 @@ Wormhole uses their contract address to create a `TokenId` for standard tokens. Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/tokens.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/tokens.ts' ``` ### Signers @@ -204,7 +204,7 @@ A `SignOnlySigner` is used when the signer isn't connected to the network or pre Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/signers.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/signers.ts' ``` #### Set Up a Signer with Ethers.js @@ -212,7 +212,7 @@ Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: ```javascript ---8<-- 'code/build/toolkit/typescript-sdk/ethers.js' +--8<-- 'code/tools/typescript-sdk/sdk-reference/ethers.js' ``` - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions @@ -247,7 +247,7 @@ The code then prepares a message for publication. This message includes: - The sender's address - The message payload (in this case, the encoded string `lol`) - A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/build/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. @@ -257,7 +257,7 @@ Lastly, the code will demonstrate how to verify the message on the receiving end ???+ code "View the complete script" ```ts - --8<-- 'code/build/toolkit/typescript-sdk/example-core-bridge.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/example-core-bridge.ts' ``` The payload contains the information necessary to perform whatever action is required based on the protocol that uses it. @@ -267,7 +267,7 @@ The payload contains the information necessary to perform whatever action is req The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/token-bridge-snippet.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge-snippet.ts' ``` Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. @@ -293,12 +293,12 @@ The transfer process is divided into three main steps: For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/token-bridge.ts:120:158' +--8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge.ts:120:158' ``` ??? code "View the complete script" ```ts hl_lines="122" - --8<-- 'code/build/toolkit/typescript-sdk/token-bridge.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge.ts' ``` Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. @@ -314,12 +314,12 @@ An optional payload can be included with the transfer, though it's set to undefi When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/cctp.ts:69:112' +--8<-- 'code/tools/typescript-sdk/sdk-reference/cctp.ts:69:112' ``` ??? code "View the complete script" ```ts - --8<-- 'code/build/toolkit/typescript-sdk/cctp.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/cctp.ts' ``` ### Recovering Transfers @@ -327,12 +327,12 @@ When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amou It may be necessary to recover an abandoned transfer before it is completed. To do this, instantiate the `Transfer` class with the `from` static method and pass one of several types of identifiers. A `TransactionId` or `WormholeMessageId` may be used to recover the transfer. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/cctp.ts:120:126' +--8<-- 'code/tools/typescript-sdk/sdk-reference/cctp.ts:120:126' ``` ??? code "View the complete script" ```ts hl_lines="130" - --8<-- 'code/build/toolkit/typescript-sdk/cctp.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/cctp.ts' ``` ## Routes @@ -344,19 +344,19 @@ To provide a more flexible and generic interface, the `Wormhole` class provides The following section demonstrates setting up and validating a token transfer using Wormhole's routing system. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/router.ts:24:31' +--8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:24:31' ``` Once created, the resolver can be used to provide a list of input and possible output tokens. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/router.ts:33:53' +--8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:33:53' ``` Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfill the request. Creating a transfer request fetches the token details since all routes will need to know about the tokens. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/router.ts:55:67' +--8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:55:67' ``` Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). @@ -366,19 +366,19 @@ After choosing the best route, extra parameters like `amount`, `nativeGasDropoff After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/router.ts:72:93' +--8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:72:93' ``` Finally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/router.ts:100:106' +--8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:100:106' ``` ??? code "View the complete script" ```ts - --8<-- 'code/build/toolkit/typescript-sdk/router.ts' + --8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts' ``` See the `router.ts` example in the [examples directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/examples){target=\_blank} for a full working example. @@ -388,7 +388,7 @@ See the `router.ts` example in the [examples directory](https://github.com/wormh Routes can be imported from any npm package that exports them and configured with the resolver. Custom routes must extend [`Route`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L21-L64){target=\_blank} and implement [`StaticRouteMethods`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L101){target=\_blank}. ```ts ---8<-- 'code/build/toolkit/typescript-sdk/custom-route.ts' +--8<-- 'code/tools/typescript-sdk/sdk-reference/custom-route.ts' ``` A noteworthy example of a route exported from a separate npm package is Wormhole Native Token Transfers (NTT). See the [`NttAutomaticRoute`](https://github.com/wormhole-foundation/native-token-transfers/blob/66f8e414223a77f5c736541db0a7a85396cab71c/sdk/route/src/automatic.ts#L48){target=\_blank} route implementation. diff --git a/tutorials/.pages b/tutorials/.pages deleted file mode 100644 index 2cd65470f..000000000 --- a/tutorials/.pages +++ /dev/null @@ -1,11 +0,0 @@ -title: Tutorials -nav: - - index.md - - connect - - multichain-assets - - multigov -# - native-token-transfers -# - settlement - - solidity-sdk - - typescript-sdk - - wormholescan diff --git a/tutorials/connect/.pages b/tutorials/connect/.pages deleted file mode 100644 index 87c55266c..000000000 --- a/tutorials/connect/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Connect -nav: - - index.md - - 'Integrate Connect into a React DApp': react-dapp.md diff --git a/tutorials/connect/index.md b/tutorials/connect/index.md deleted file mode 100644 index 9644d8cbe..000000000 --- a/tutorials/connect/index.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Wormhole Connect Tutorials -description: Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -categories: Connect, Transfer ---- - -# Connect - -Wormhole Connect makes it simple to link your application to multiple blockchain ecosystems. These tutorials will teach you how to integrate Connect into your projects, streamline cross-chain interactions, simplify user onboarding, and deliver a smoother overall experience. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Integrate Connect into a React DApp** - - --- - - Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - - [:custom-arrow: Start building](/docs/tutorials/connect/react-dapp/) - -
- -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Connect** - - --- - - Get deeper insights into setting up and customizing Wormhole Connect. Explore advanced guides, best practices, and configuration tips to streamline your cross-chain integrations. - - [:custom-arrow: Learn more](/docs/build/transfers/connect/) - -
\ No newline at end of file diff --git a/tutorials/index.md b/tutorials/index.md deleted file mode 100644 index d8e6e0099..000000000 --- a/tutorials/index.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Tutorials -description: Discover product-specific Wormhole tutorials. Learn setup, integration, and advanced features to develop cross-chain apps confidently. -template: root-index-page.html ---- - -# Tutorials - -In this section, you'll find tutorials focused on individual Wormhole products. Each product folder contains detailed guides to help you integrate and use specific Wormhole services, such as Token Bridge, Wormhole Connect, and more. Whether setting up your first product or diving deeper into advanced features, these tutorials will walk you through the entire process, from installation to implementation. - -## Browse Tutorials by Product - -## Get Started - -
- -- :octicons-arrow-switch-16:{ .lg .middle } **Connect** - - --- - - With Wormhole Connect, you can enable seamless connectivity between different blockchain ecosystems. These tutorials guide you through integrating Connect into your projects, allowing you to easily leverage cross-chain interactions, simplify onboarding, and improve user experience. - - [:custom-arrow: Start building](/docs/tutorials/connect/) - -- :octicons-sync-16:{ .lg .middle } **Multichain Assets** - - --- - - Learn how to create, register, and manage wrapped multichain assets across multiple chains. These tutorials will guide you through the process of enabling asset transfers between supported networks. - - [:custom-arrow: Start building](/docs/tutorials/multichain-assets/) - -- :octicons-people-16:{ .lg .middle } **MultiGov** - - --- - - Unleash the power of cross-chain governance with Multigov. These tutorials guide you through setting up and managing governance structures spanning multiple blockchains, enabling collective decision-making and coordinated upgrades across decentralized ecosystems. - - [:custom-arrow: Start building](/docs/tutorials/multigov/) - -- :octicons-file-code-16:{ .lg .middle } **Solidity SDK** - - --- - - Learn to build smart contracts that communicate across multiple blockchains. These tutorials show you how to create robust cross-chain contracts, allowing your dApps to move beyond a single network and tap into global liquidity, functionality, and user bases. - - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/) - -- :octicons-code-square-16:{ .lg .middle } **TypeScript SDK** - - --- - - Master the tools to build cross-chain applications with the Wormhole SDK. These tutorials cover installation to advanced functionality, helping you streamline development, reduce complexity, and quickly bring your ideas to life. - - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/) - -- :octicons-code-square-16:{ .lg .middle } **Wormholescan API** - - --- - - Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. - - [:custom-arrow: Start building](/docs/tutorials/wormholescan/) - -
diff --git a/tutorials/multichain-assets/.pages b/tutorials/multichain-assets/.pages deleted file mode 100644 index d9e4bdb7f..000000000 --- a/tutorials/multichain-assets/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Multichain Assets -nav: - - index.md - - 'Create Multichain Tokens': 'multichain-token.md' diff --git a/tutorials/multichain-assets/index.md b/tutorials/multichain-assets/index.md deleted file mode 100644 index 6564f9326..000000000 --- a/tutorials/multichain-assets/index.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Multichain Assets Tutorials -description: Explore comprehensive, step-by-step tutorials on how to register, manage, and work with multichain assets within the Wormhole ecosystem. ---- - -# Multichain Assets - -Multichain assets, often represented as wrapped tokens, enable seamless cross-chain interoperability. This section provides step-by-step tutorials for registering, managing, and working with these assets across different blockchains. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Create Multichain Tokens** - - --- - - Learn how to register your token on both a source and target chain, and create a wrapped version for seamless interoperability. - - [:custom-arrow: Register your assets now](/docs/tutorials/multichain-assets/multichain-token/) - -
\ No newline at end of file diff --git a/tutorials/multigov/.pages b/tutorials/multigov/.pages deleted file mode 100644 index fd0b0708f..000000000 --- a/tutorials/multigov/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: MultiGov -nav: - - index.md - - 'Cross-Chain Treasury Management Proposal': 'treasury-proposal.md' diff --git a/tutorials/multigov/index.md b/tutorials/multigov/index.md deleted file mode 100644 index 97ab3c777..000000000 --- a/tutorials/multigov/index.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Step-by-Step MultiGov Tutorials -description: Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. -categories: MultiGov ---- - -# MultiGov - -Welcome to the MultiGov tutorials section. In this section, you will find tutorials that walk you through the key steps of working with MultiGov, providing clear instructions to help you get started. As you explore, you'll gain a deeper understanding of MultiGov's features and functionality. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Cross-Chain Treasury Management Proposal** - - --- - - Learn how to propose governance actions on a hub chain, gather votes from spoke chains, aggregate the results, and carry out the final decision. Following these steps, you’ll master end-to-end governance workflows spanning multiple networks. - - [:custom-arrow: Start building](/docs/tutorials/multigov/treasury-proposal/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Governance Fundamentals** - - --- - - Dive into Wormhole’s governance mechanisms. Understand how cross-chain governance works, proposal creation, voting, and execution. - - [:custom-arrow: Explore governance](/docs/learn/governance/) - -- :octicons-tools-16:{ .lg .middle } **Implement MultiGov** - - --- - - Integrate MultiGov into your smart contracts. Access reference code, best practices, and guidance for deploying cross-chain governance systems. - - - [:custom-arrow: Build with MultiGov](/docs/build/multigov/) - -
diff --git a/tutorials/settlement/.index.md b/tutorials/settlement/.index.md deleted file mode 100644 index b54bc93d0..000000000 --- a/tutorials/settlement/.index.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Wormhole Settlement -description: Follow step-by-step tutorials to integrate Wormhole Settlement Routes using the SDK for seamless cross-chain swaps and efficient asset transfers. ---- - -# Wormhole Settlement - -This section provides hands-on tutorials to help you integrate Wormhole Settlement Routes into your application. Learn how to use the SDK to manage cross-chain swaps, optimize fees, and streamline transaction execution. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Integrate Wormhole Settlement Routes using the SDK** - - --- - - Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. - - [:custom-arrow: Integrate Settlement Routes](/docs/tutorials/settlement/settlement-routes/) - -
\ No newline at end of file diff --git a/tutorials/settlement/.pages b/tutorials/settlement/.pages deleted file mode 100644 index 392d75ad7..000000000 --- a/tutorials/settlement/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Settlement -nav: - - index.md - - 'Integrate Settlement Routes using the SDK': 'settlement-routes.md' - diff --git a/tutorials/solidity-sdk/.pages b/tutorials/solidity-sdk/.pages deleted file mode 100644 index bbab734c3..000000000 --- a/tutorials/solidity-sdk/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: Solidity SDK -nav: - - index.md - - 'Create Messaging Contracts': 'cross-chain-contracts.md' - - 'Create Token Transfer Contracts': 'cross-chain-token-contracts.md' \ No newline at end of file diff --git a/tutorials/solidity-sdk/index.md b/tutorials/solidity-sdk/index.md deleted file mode 100644 index c74601071..000000000 --- a/tutorials/solidity-sdk/index.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Solidity SDK Tutorials -description: Master cross-chain smart contracts with Wormhole's Solidity SDK. Learn messaging, token transfers, and secure, scalable dApp deployments across blockchains. ---- - -# Solidity SDK - -Expand the reach of your decentralized applications by building smart contracts that can communicate across multiple blockchains. Through these tutorials, you’ll learn to create robust cross-chain contracts, enabling your dApps to tap into global liquidity, diverse functionalities, and a broader user base. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Messaging Contracts** - - --- - - Learn how to build and deploy smart contracts that communicate seamlessly across multiple blockchains. This tutorial walks you through using Wormhole's Solidity SDK to send and receive messages between Avalanche Fuji and Celo Alfajores, helping you master emitter validation, relayer usage, and cross-chain cost management. - - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-contracts/) - -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Token Transfer Contracts** - - --- - - Discover how to create a fully functional cross-chain token transfer system using Wormhole's Solidity SDK. This tutorial guides you through token attestation, contract deployment, and secure transfers of ERC-20 tokens between test networks. By the end, you’ll know how to tap into global liquidity and enrich your dApps with seamless multi-chain asset movement. - - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Core Contracts** - - --- - - Dive deeper into Wormhole’s foundational concepts for cross-chain contracts. Discover how messaging, guardians, and VAAs work together to enable secure, scalable dApps. - - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) - -
diff --git a/tutorials/typescript-sdk/.pages b/tutorials/typescript-sdk/.pages deleted file mode 100644 index fd96b0f2d..000000000 --- a/tutorials/typescript-sdk/.pages +++ /dev/null @@ -1,5 +0,0 @@ -title: TypeScript SDK -nav: - - index.md - - 'Transfer USDC via the CCTP Bridge': 'usdc-via-cctp.md' - - 'Transfer Tokens via the Token Bridge': 'tokens-via-token-bridge.md' diff --git a/tutorials/typescript-sdk/index.md b/tutorials/typescript-sdk/index.md deleted file mode 100644 index 5631f94d3..000000000 --- a/tutorials/typescript-sdk/index.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Wormhole SDK Tutorials -description: Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. ---- - -# Wormhole SDK - -The Wormhole SDK provides the essential building blocks for creating robust cross-chain applications. With its developer-friendly libraries, tools, and interfaces, you can quickly integrate Wormhole’s messaging, token transfer, and governance functionalities into your projects. Whether you’re building a simple cross-chain dApp or architecting a complex multi-chain ecosystem, these tutorials will guide you through mastering the SDK and unlocking the full potential of Wormhole’s infrastructure. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Transfer USDC via CCTP** - - --- - - Learn how to move native USDC across chains using Circle’s CCTP and Wormhole’s TypeScript SDK. This tutorial shows you how to streamline transfers with automated attestation and finalization or take complete control with manual steps. Gain the skills to handle seamless USDC bridging, optimize user experience, and improve the reliability of your cross-chain applications. - - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/usdc-via-cctp/) - -- :octicons-repo-16:{ .lg .middle } **Transfer Tokens via the Token Bridge** - - --- - - Learn how to build a versatile cross-chain token transfer application using Wormhole’s TypeScript SDK. This tutorial walks you through leveraging the Token Bridge to securely and efficiently move assets between EVM and non-EVM chains. By the end, you’ll understand how to transfer tokens between networks like Ethereum, Solana, Sui, and beyond, opening the door to an interconnected blockchain ecosystem. - - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/) - -
- -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Wormhole SDK Documentation** - - --- - - Learn to build cross-chain dApps using the Wormhole SDK. Access detailed guides, reference code, and best practices for robust application development. - - [:custom-arrow: Learn more](/docs/build/toolkit/typescript-sdk/) - -
\ No newline at end of file diff --git a/tutorials/wormholescan/.pages b/tutorials/wormholescan/.pages deleted file mode 100644 index 6f4cb4b0b..000000000 --- a/tutorials/wormholescan/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Wormholescan API -nav: - - index.md - - 'Replace VAA Signatures': 'replace-signatures.md' \ No newline at end of file diff --git a/tutorials/wormholescan/index.md b/tutorials/wormholescan/index.md deleted file mode 100644 index 2344819c2..000000000 --- a/tutorials/wormholescan/index.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Wormholescan API Tutorials -description: Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. ---- - -# Wormholescan API - -Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Replace Outdated Signatures in VAAs** - - --- - - Learn how to fetch VAAs, verify their validity, and replace outdated signatures using the Wormholescan API and Wormhole SDK. - - [:custom-arrow: Start tutorial](/docs/tutorials/wormholescan/replace-signatures/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Wormholescan** - - --- - - Wormholescan is a blockchain explorer for tracking transactions, VAAs, and cross-chain activity. Its API provides programmatic access to transaction data, network analytics, and more. - - [:custom-arrow: Visit Wormholescan](https://wormholescan.io/){target=\_blank} - -
\ No newline at end of file From a149aa961350446b8ac93e590cebce711f28c056 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Thu, 24 Apr 2025 01:27:25 -0400 Subject: [PATCH 03/55] update llms --- llms-files/llms-basics.txt | 2600 +- llms-files/llms-connect.txt | 4230 ++-- llms-files/llms-multigov.txt | 4291 ++-- llms-files/llms-ntt.txt | 5643 +++-- llms-files/llms-queries.txt | 3268 ++- llms-files/llms-reference.txt | 382 +- llms-files/llms-relayers.txt | 3169 ++- llms-files/llms-settlement.txt | 3250 ++- llms-files/llms-solidity-sdk.txt | 3206 ++- llms-files/llms-token-bridge.txt | 3256 ++- llms-files/llms-transfer.txt | 9655 ++++---- llms-files/llms-typescript-sdk.txt | 3158 ++- llms-full.txt | 33980 +++++++++++++-------------- llms.txt | 184 +- 14 files changed, 38183 insertions(+), 42089 deletions(-) diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index 2463ef118..deea21c34 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -6,2094 +6,2026 @@ It is intended for use with large language models (LLMs) to support developers w This file includes documentation related to the category: Basics ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: - -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +🛠 **Wormhole products used:** -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -## Next Steps +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** - --- +
+
- Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## Cross-Chain Perpetuals - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +
+
- --- +🛠 **Wormhole products used:** - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +
-# Architecture -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +## Gas Abstraction -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +
+
-1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +🛠 **Wormhole products used:** - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -## On-Chain Components +
+
-- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +## Bridging Intent Library -## Next Steps +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Multichain Prediction Markets - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- +
-# Core Contracts +🛠 **Wormhole products used:** -## Introduction +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +
+
-## Key Functions -Key functions of the Wormhole Core Contract include the following: +
+
-- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +## Cross-Chain Payment Widgets -## How the Core Contract Works +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +🛠 **Wormhole products used:** -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -### Message Submission +
+
-You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +
+
-There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +## Oracle Networks -### Message Reception +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - -## Multicast - -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. - -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +# Glossary -The following sections explore each principle in detail. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -### Decentralization +## Chain ID -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Two common approaches to decentralization have notable limitations: +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Consistency Level -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Delivery Provider -To answer that, consider these key constraints and design decisions: +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Emitter -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -### Modularity +## Finality -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -### Chain Agnosticism +## Guardian -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -### Scalability +## Guardian Network -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## Guardian Set -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Upgradeable +## Heartbeat -Wormhole is designed to adapt and evolve in the following ways: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Observation -## Next Steps +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -
+## Relayer -- :octicons-book-16:{ .lg .middle } **Relayers** +A relayer is any process that delivers VAAs to a destination. - --- +## Sequence - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +## Spy -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Prerequisites -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +To interact with the Wormhole Core Contract, you'll need the following: -## Fundamentals +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +## How to Interact with Core Contracts -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -Key characteristics of VAAs include: +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Public emission from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Authentication through signatures from the Guardian Network +### Sending Messages -- Verifiability by any entity or any Wormhole Core Contract +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +=== "EVM" -Keep in mind the following security considerations around relayers: + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ??? interface "Parameters" -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Client-Side Relaying + --- -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -### Key Features + --- -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + ??? interface "Returns" -### Implementation + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -Users themselves carry out the three steps of the cross-chain process: + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -1. Perform an action on chain A +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -2. Retrieve the resulting VAA from the Guardian Network +// Check fee and send parameters -3. Perform an action on chain B using the VAA +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -### Considerations +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- Users must sign all required transactions with their own wallet + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- Users must have funds to pay the transaction fees on every chain involved +=== "Solana" -- The user experience may be cumbersome due to the manual steps involved + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -## Custom Relayers + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + ??? interface "Parameters" -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -### Key Features + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ??? child "Type `PostMessage<'info>`" -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -### Implementation + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `batch_id` ++"u32"++ + + An identifier for the message batch. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + --- -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -## Wormhole Relayers + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -### Key Features + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -### Implementation + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -The Wormhole relayer integration involves two key steps: +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +### Receiving Messages -### Considerations +The way a message is received and handled depends on the environment. -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +=== "EVM" -- All computations are performed on-chain + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Potentially less gas-efficient compared to custom relayers + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ??? interface "Parameters" -- Support may not be available for all chains + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -## Next Steps + ??? interface "Returns" -
+ `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -- :octicons-book-16:{ .lg .middle } **Spy** + ??? child "Struct `VM`" - --- + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - --- + ??? interface "Example" - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + // Perform safety checks here -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - --- + // Your custom application logic here +} + ``` - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +=== "Solana" -
---- END CONTENT --- + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- + Retrieve the raw message data: -# Spy + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + ??? interface "Example" -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -## Key Features + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure +#### Validating the Emitter -## Integrator Use Case +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -## Observable Message Categories +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -A Spy can access the following categories of messages shared over the gossip protocol: +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +await tx.wait(); +``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +#### Additional Checks -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +## Source Code References -## Additional Resources +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- - --- +# Wormhole Relayer - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +## Introduction - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. - --- +## Get Started with the Wormhole Relayer - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- --- +### Wormhole Relayer Interfaces - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -
+## Interact with the Wormhole Relayer -## Next Steps +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -
+To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. - --- +Your initial set up should resemble the following: - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -- :octicons-code-16:{ .lg .middle } **Use Queries** +contract Example { + IWormholeRelayer public wormholeRelayer; - --- + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +### Send a Message -
---- END CONTENT --- +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -# Verified Action Approvals +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -## VAA Format +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -The basic VAA consists of header and body components described as follows: +### Receive a Message -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). - Where each `signature` is: +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +## Delivery Guarantees -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -## Consistency and Finality +## Delivery Statuses -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Signatures +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -## Payload Types +## Other Considerations -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -### Token Transfer +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +## Track the Progress of Messages with the Wormhole CLI -Transferring tokens from the sending chain to the destination chain requires the following steps: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +=== "Mainnet" -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer +=== "Testnet" -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -### Attestation +## Step-by-Step Tutorial -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -The message format for token attestation is as follows: +# Products -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -#### Attestation Tips +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Be aware of the following considerations when working with attestations: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +## Transfer Products -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +
-- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +::spantable:: -### Token Transfer with Message +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +::end-spantable:: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +
-This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +## Real-time Data -### Governance +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +## Multichain Governance -#### Action Structure +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +# Architecture -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +## Overview -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -#### Actions +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Lifetime of a Message + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +## On-Chain Components -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers ## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +### Message Reception -## Use Cases of Wormhole +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Consider the following examples of potential applications enabled by Wormhole: +## Multicast -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -## Explore +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -Discover more about the Wormhole ecosystem, components, and protocols: +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -## Demos +## Next Steps -Demos offer more realistic implementations than tutorials: +
-- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -!!! note - Wormhole Integration Complete? + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** + --- -## Supported Blockchains + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -Wormhole supports a growing number of blockchains. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - - -
+
+--- END CONTENT --- -### EVM +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- ---- END CONTENT --- +## Guardian -Doc-Content: https://wormhole.com/docs/protocol/security/ ---- BEGIN CONTENT --- ---- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics ---- +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -# Security +Guardians fulfill their role in the messaging protocol as follows: -## Core Security Assumptions +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +## Guardian Network -In summary: +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +The Guardian Network is designed to help Wormhole deliver on five key principles: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -## Guardian Network +The following sections explore each principle in detail. -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +### Decentralization -### Governance +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +Two common approaches to decentralization have notable limitations: -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -Via governance, the Guardians can: +To answer that, consider these key constraints and design decisions: -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -## Monitoring +### Modularity -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +### Chain Agnosticism -Guardians monitor: +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +### Scalability -## Asset Layer Protections +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +### Upgradeable -## Open Source +Wormhole is designed to adapt and evolve in the following ways: -Wormhole builds in the open and is always open source. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -## Audits +## Next Steps -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +
-- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +- :octicons-book-16:{ .lg .middle } **Relayers** -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + --- -## Bug Bounties + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + --- -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. -## Learn More + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. categories: Basics --- -# Get Started with Core Contracts - -## Introduction - -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. - -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - -## Prerequisites +# Relayers -To interact with the Wormhole Core Contract, you'll need the following: +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. -## How to Interact with Core Contracts +There are three primary types of relayers discussed: -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient -### Sending Messages +## Fundamentals -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. -=== "EVM" +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +Key characteristics of VAAs include: - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +- Public emission from the Guardian Network - ??? interface "Parameters" +- Authentication through signatures from the Guardian Network - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +- Verifiability by any entity or any Wormhole Core Contract - --- +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +Keep in mind the following security considerations around relayers: - --- +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - ??? interface "Returns" +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Client-Side Relaying - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +### Key Features -// Check fee and send parameters +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); +### Implementation -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +Users themselves carry out the three steps of the cross-chain process: - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +1. Perform an action on chain A -=== "Solana" +2. Retrieve the resulting VAA from the Guardian Network - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: +3. Perform an action on chain B using the VAA - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +### Considerations - ??? interface "Parameters" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +- Users must sign all required transactions with their own wallet - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +- Users must have funds to pay the transaction fees on every chain involved - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +- The user experience may be cumbersome due to the manual steps involved - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +## Custom Relayers - ??? child "Type `PostMessage<'info>`" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +### Key Features - --- +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - `batch_id` ++"u32"++ - - An identifier for the message batch. +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - --- +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - --- +### Implementation - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +### Considerations - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +- Development work and hosting of relayers are required -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- Relayers are responsible for availability, and adding dependencies for the cross-chain application - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +## Wormhole Relayers -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +### Key Features -### Receiving Messages +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -The way a message is received and handled depends on the environment. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -=== "EVM" +### Implementation - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +The Wormhole relayer integration involves two key steps: - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract - ??? interface "Parameters" +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +### Considerations - ??? interface "Returns" +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +- All computations are performed on-chain - ??? child "Struct `VM`" +- Potentially less gas-efficient compared to custom relayers - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Support may not be available for all chains - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +## Next Steps - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +
- ??? interface "Example" +- :octicons-book-16:{ .lg .middle } **Spy** - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); + --- - // Perform safety checks here + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - // Your custom application logic here -} - ``` +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - Retrieve the raw message data: +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` + --- - ??? interface "Example" + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +
+--- END CONTENT --- - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -#### Validating the Emitter +# Spy -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +## Key Features -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -await tx.wait(); -``` +## Integrator Use Case -#### Additional Checks +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +## Observable Message Categories -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +A Spy can access the following categories of messages shared over the gossip protocol: -## Source Code References +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -# Wormhole Relayer +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -## Introduction + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +## Additional Resources -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. +
-## Get Started with the Wormhole Relayer +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + --- -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -### Wormhole Relayer Interfaces +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + --- -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -## Interact with the Wormhole Relayer + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + --- -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -Your initial set up should resemble the following: + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +
-import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +## Next Steps -contract Example { - IWormholeRelayer public wormholeRelayer; +
- constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +- :octicons-code-16:{ .lg .middle } **Run a Spy** -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. + --- -### Send a Message + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. + --- -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +
+--- END CONTENT --- -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +--- BEGIN CONTENT --- +--- +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics +--- -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +# Verified Action Approvals -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -### Receive a Message +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -## Delivery Guarantees +## VAA Format -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. +The basic VAA consists of header and body components described as follows: -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + Where each `signature` is: -## Delivery Statuses + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: +- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. +## Consistency and Finality -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -## Other Considerations +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +## Signatures -- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Track the Progress of Messages with the Wormhole CLI +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -=== "Mainnet" +## Payload Types - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -=== "Testnet" +### Token Transfer - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +Transferring tokens from the sending chain to the destination chain requires the following steps: -## Step-by-Step Tutorial +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. ---- END CONTENT --- +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -Doc-Content: https://wormhole.com/docs/build/start-building/products/ ---- BEGIN CONTENT --- ---- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics ---- +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -# Products +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +### Attestation -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -## Transfer Products +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The message format for token attestation is as follows: -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset -
+#### Attestation Tips -::spantable:: +Be aware of the following considerations when working with attestations: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -::end-spantable:: +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -## Real-time Data +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +### Token Transfer with Message -## Multichain Governance +The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -# Wormhole Use Cases +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -
-
+### Governance -## Cross-Chain Swaps and Liquidity Aggregation +Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -Enable seamless swaps between chains with real-time liquidity routing. +#### Action Structure -
-
+Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: -🛠 **Wormhole products used:** +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` -
-
+#### Actions +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: -
-
+- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -## Borrowing and Lending Across Chains +## Lifetime of a Message -Let users borrow assets on one chain using collateral from another. +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -🛠 **Wormhole products used:** +1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +## Next Steps -
-
+
+- :octicons-book-16:{ .lg .middle } **Guardians** -
-
+ --- -## Real-Time Price Feeds and Trading Strategies + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -Fetch price feeds across multiple chains for DeFi applications. + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) -
-
+- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -🛠 **Wormhole products used:** + --- -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -
-
+# Introduction to Wormhole -## Asset Movement Between Bitcoin and Other Chains +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -Enable direct BTC transfers without wrapped assets. +Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. -
-
+Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -🛠 **Wormhole products used:** +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -
-
+## What Problems Does Wormhole Solve? -## Decentralized Social Platforms +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -Enable seamless communication and asset transfer across decentralized social networks. +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions -🛠 **Wormhole products used:** +## What Does Wormhole Offer? -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards +Wormhole provides a suite of tools and protocols that support a wide range of use cases: -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -
-
+## What Isn't Wormhole? +- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -
-
+## Use Cases of Wormhole -## Memecoin Launchpads +Consider the following examples of potential applications enabled by Wormhole: -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore -🛠 **Wormhole products used:** +Discover more about the Wormhole ecosystem, components, and protocols: -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +## Demos -
-
+Demos offer more realistic implementations than tutorials: +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -
-
+ -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! -🛠 **Wormhole products used:** + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +## Supported Blockchains -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Wormhole supports a growing number of blockchains. -
-
+ + +
+### EVM -
-
+| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -## Gas Abstraction +### SVM -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM -🛠 **Wormhole products used:** +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +### CosmWasm -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### Move VM +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### NEAR VM -## Bridging Intent Library +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
+ +--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents +# Security -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -
-
+In summary: -## Multichain Prediction Markets +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. +Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. -
-
+## Guardian Network -🛠 **Wormhole products used:** +Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### Governance -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -
-
+All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -## Cross-Chain Payment Widgets +Via governance, the Guardians can: -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -
-
+The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -🛠 **Wormhole products used:** +## Monitoring -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. -
-
+Guardians monitor: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -
-
+## Asset Layer Protections -## Oracle Networks +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -
-
+In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -🛠 **Wormhole products used:** +## Open Source -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +Wormhole builds in the open and is always open source. -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** -
-
+## Audits +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -
-
+- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} -## Cross-Chain Staking +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. -Enable users to stake assets on one chain while earning rewards or securing networks on another. +## Bug Bounties -
-
+Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -🛠 **Wormhole products used:** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. -
-
+## Learn More + +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index 3a810a527..0832993a3 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -13,21 +13,204 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/transfers/connect/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ +--- BEGIN CONTENT --- +--- +title: Integrate Connect into a React DApp Tutorial +description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +categories: Connect, Transfer +--- + +# Integrate Connect into a React DApp + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. + +While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. + +## Prerequisites + +To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. +Before starting this tutorial, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use +- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} +- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees + +## Set Up Connect for Sui Transfers + +### Create a React Project + +Start by setting up your React app: + +1. Open your terminal and run the following command to create a new React app: + + ```bash + npx create-react-app connect-tutorial + ``` + +2. Navigate into the project directory: + + ```bash + cd connect-tutorial + ``` + +### Install Wormhole Connect + +Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: + +```bash +npm install @wormhole-foundation/wormhole-connect +``` + +### Integrate Connect into the Application + +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: + +=== "JavaScript" + + ```js + import logo from './logo.svg'; + import './App.css'; + import WormholeConnect from '@wormhole-foundation/wormhole-connect'; + + const config = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + }; + + function App() { + return ; + } + + export default App; + ``` + +=== "TypeScript" + + ```ts + import './App.css'; + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + } from '@wormhole-foundation/wormhole-connect'; + + function App() { + const config: WormholeConnectConfig = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + }; + + return ; + } + + export default App; + ``` + +- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment +- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche + +### Customize Wormhole Connect + +To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. + +### Run the Application + +Make sure you’re in the root directory of your React app, and run the following command to start the application: + +```bash +npm start +``` + +Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. + +## Transfer Tokens from Sui to Fuji + +Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. + +To transfer tokens from Sui to Fuji in the Wormhole Connect interface: + +1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer +2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network +3. Enter the amount of SUI tokens you wish to transfer + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) + +4. Choose to view other routes + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) + +5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) + + !!! note + It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) + +6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) + +7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) + +Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Claim Tokens on Fuji + +After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. + +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) + +Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. + +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) + +## Resources + +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. + +## Conclusion + +In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. + +By following these steps, you've learned how to: + +- Set up a React project tailored for cross-chain transfers +- Install and configure Wormhole Connect to support multiple blockchains +- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers +- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks + +With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ --- BEGIN CONTENT --- --- title: Wormhole Connect @@ -94,77 +277,216 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/ +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ --- BEGIN CONTENT --- --- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. +title: Overview +description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. categories: Connect, Transfer --- # Wormhole Connect -## Configure Connect +## Introduction {: #introduction } -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. +Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. +The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. -!!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. +## Features {: #features } - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}. +Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -
+- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) +- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) +- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer +- Ability to configure any token to bridge via Wormhole +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -- :octicons-database-16:{ .lg .middle } **Data** +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. - --- +## Integrate Connect {: #integrate-connect } - Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. +### Import Directly into a React App {: #import-directly-into-a-react-app} +First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - [:custom-arrow: Get started](/docs/products/connect/configuration/data/) +```bash +npm i @wormhole-foundation/wormhole-connect +``` -- :octicons-apps-16:{ .lg .middle } **Theme** +Now you can import the React component: - --- +```ts +import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. +function App() { + return ; +} +``` - [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/) +### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} -
---- END CONTENT --- +If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. -Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ ---- BEGIN CONTENT --- ---- -title: Connect Data Configuration -description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. -categories: Connect, Transfer ---- +```ts title="v1.x" +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -## Data Configuration +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); -This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +wormholeConnectHosted(container); +``` -## Get Started +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. -Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. +???- code "v0.x" + Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. -=== "React integration" + ```html + +
+ + + + ``` - ```ts - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', + ```html + +
+ + + + ``` + +It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. + +## Configuration {: #configuration} + +This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. + +The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: + + - Use custom styles + - Restrict the chains that you allow in your app + - Add support for your project's token, and eliminate tokens you don't want to reduce noise + - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available + +For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ +--- BEGIN CONTENT --- +--- +title: Routes +description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +categories: Connect, Transfer +--- + +## Routes Overview {: #routes-overview} + +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. + +Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. + +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. + +## Token Bridge Routes {: #token-bridge-routes} + +The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. + +#### Manual Route {: #manual-route} + +The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. + +#### Automatic Route {: #automatic-route} + +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. + +## CCTP Routes (USDC) {: #cctp-routes-usdc} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. + +Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. + +#### Manual Route {: #manual-route-cctp} + +This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. + +#### Automatic Route {: #automatic-route-cctp} + +Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. + +## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} + +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. + +#### Manual Route {: #manual-route-ntt} + +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. + +#### Automatic Route {: #automatic-route-ntt} + +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. + +## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} + +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). + +#### Automatic Route {: #automatic-route-eth} + +Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. + +## USDT Bridge Route {: #usdt-bridge-route} + +Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. + +#### Automatic Route {: #automatic-route-usdt} + +Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. + +## tBTC Route {: #tbtc-route} + +You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). + +Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. + +#### Manual Route {: #manual-route-tbtc} + +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ +--- BEGIN CONTENT --- +--- +title: Connect Data Configuration +description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +categories: Connect, Transfer +--- + +## Data Configuration + +This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. + +## Get Started + +Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. + +=== "React integration" + + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', Solana: 'https://rpc.ankr.com/solana', } } @@ -294,7 +616,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -652,7 +974,7 @@ categories: Connect, Transfer ## What types of assets does Connect support? -Wormhole Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: +Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: - Major stablecoins like USDT and USDC (via CCTP) - Native gas tokens such as ETH, SOL, etc. @@ -682,9 +1004,9 @@ Connect can be [fully customized](https://connect-in-style.wormhole.com/){target Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. -## Do integrators need to enable wallets like Phantom or Backpack in Wormhole Connect? +## Do integrators need to enable wallets like Phantom or Backpack in Connect? -Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Wormhole Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. +Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. ## Which function should be modified to set priority fees for Solana transactions? @@ -714,367 +1036,96 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- -title: Features -description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. +title: Wormhole Connect v1.0 Migration Guide +description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. categories: Connect, Transfer --- -## Feature Support Matrix {: #feature-support-matrix} - -*Scroll down for details about each column.* +# Wormhole Connect v1.0 Migration Guide -| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | -|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| -| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | -| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | -| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | -| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | -| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | -| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | -| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | -| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | -| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | -| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | -| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | -| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | -| Base | ✅ | ✅ | ✅ | ✅ | ✅ | -| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | -| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | -| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | -| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | +## Overview -## Feature Explanation {: #feature-explanation} +The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. -### Token Bridge {: #token-bridge} +This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: -Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. + - Update to the latest Connect package + - Apply configuration changes to the **`WormholeConnectConfig`** object + - Understand new routing capabilities and plugin options -This route appears if both of the following conditions are satisfied: +These updates ensure better performance and a smoother integration experience. - - Both the origin and destination chains support Token Bridge - - No non-Token Bridge routes are available for the selected token +## Update the Connect Package -### Token Bridge Relayer {: #token-bridge-relayer} +To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. -On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +Run the following command in your terminal: -Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. +```bash +npm install @wormhole-foundation/wormhole-connect@^1.0 +``` -This route appears if all of the following conditions are satisfied: +This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. -- Both the origin and destination chains support Token Bridge -- Both the origin and destination chains support Token Bridge relayer -- No non-Token Bridge routes are available for the selected token -- The relayer supports the selected token on the origin chain +## Update the `WormholeConnectConfig` Object -### Circle CCTP {: #circle-cctp} +In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. +### Summary of Breaking Changes -This route appears if all of the following conditions are satisfied: +- Chain names are now capitalized: `solana` → `Solana` +- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` +- `networks` renamed to `chains`, with capitalized names +- `routes` updated to use route plugins +- `nttGroups` removed in favor of route plugin configuration +- `tokensConfig` updated, with a new key `wrappedTokens` added +- Many UI-related properties consolidated under a top-level `ui` key +- `customTheme` and `mode` were removed, replaced by a top-level `theme` property -- Both the origin and destination chains support Circle CCTP -- The selected token is native Circle-issued USDC +These changes are explained in more detail below, with examples for easy reference. -### ETH Bridge {: #eth-bridge} +### Capitalize Chain Names -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. +In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. -This route appears if all of the following conditions are satisfied: +=== "v0.x" -- Both the origin and destination chains support the ETH Bridge -- The selected token is native ETH, wstETH, or canonical wETH + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + ethereum: 'INSERT_ETH_RPC_URL', + solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` +=== "v1.x" -### Gas Drop Off {: #gas-drop-off} + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + Ethereum: 'INSERT_ETH_RPC_URL', + Solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` -A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. +You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. -This route appears if all of the following conditions are satisfied: +### Rename `env` to `network` -- Both the origin and destination chains support gas drop off -- An automatic route is selected -- The relayer accepts the selected token to swap into the gas token ---- END CONTENT --- +The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. -Doc-Content: https://wormhole.com/docs/build/transfers/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- +=== "v0.x" -# Wormhole Connect - -## Introduction {: #introduction } - -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. - -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. - -## Features {: #features } - -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: - -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination - -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. - -## Integrate Connect {: #integrate-connect } - -### Import Directly into a React App {: #import-directly-into-a-react-app} - -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - -```bash -npm i @wormhole-foundation/wormhole-connect -``` - -Now you can import the React component: - -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - -function App() { - return ; -} -``` - -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} - -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. - -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; - -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); - -wormholeConnectHosted(container); -``` - -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. - -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. - - ```html - -
- - - - ``` - - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: - - ```html - -
- - - - ``` - -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. - -## Configuration {: #configuration} - -This is just an overview of what's possible. Check the [Configuration docs](/docs/build/transfers/connect/configuration/){target=\_blank} for details about all the configuration options. - -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: - - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available - -For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ ---- BEGIN CONTENT --- ---- -title: Routes -description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -categories: Connect, Transfer ---- - -## Routes Overview {: #routes-overview} - -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/build/transfers/connect/configuration/){target=\_blank}. - -Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. - -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. - -## Token Bridge Routes {: #token-bridge-routes} - -The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. - -#### Manual Route {: #manual-route} - -The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. - -#### Automatic Route {: #automatic-route} - -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. - -## CCTP Routes (USDC) {: #cctp-routes-usdc} - -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. - -Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. - -#### Manual Route {: #manual-route-cctp} - -This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. - -#### Automatic Route {: #automatic-route-cctp} - -Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. - -## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} - -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/build/transfers/connect/configuration/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. - -#### Manual Route {: #manual-route-ntt} - -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. - -#### Automatic Route {: #automatic-route-ntt} - -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. - -## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} - -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). - -#### Automatic Route {: #automatic-route-eth} - -Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. - -## USDT Bridge Route {: #usdt-bridge-route} - -Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. - -#### Automatic Route {: #automatic-route-usdt} - -Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. - -## tBTC Route {: #tbtc-route} - -You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). - -Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. - -#### Manual Route {: #manual-route-tbtc} - -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect v1.0 Migration Guide -description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -categories: Connect, Transfer ---- - -# Wormhole Connect v1.0 Migration Guide - -## Overview - -The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. - -This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: - - - Update to the latest Connect package - - Apply configuration changes to the **`WormholeConnectConfig`** object - - Understand new routing capabilities and plugin options - -These updates ensure better performance and a smoother integration experience. - -For complete documentation on the previous version of Wormhole Connect, please refer to the [Wormhole Connect guide](/docs/build/transfers/connect/){target=\_blank}. - -## Update the Connect Package - -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. - -Run the following command in your terminal: - -```bash -npm install @wormhole-foundation/wormhole-connect@^1.0 -``` - -This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. - -## Update the `WormholeConnectConfig` Object - -In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. - -### Summary of Breaking Changes - -- Chain names are now capitalized: `solana` → `Solana` -- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` -- `networks` renamed to `chains`, with capitalized names -- `routes` updated to use route plugins -- `nttGroups` removed in favor of route plugin configuration -- `tokensConfig` updated, with a new key `wrappedTokens` added -- Many UI-related properties consolidated under a top-level `ui` key -- `customTheme` and `mode` were removed, replaced by a top-level `theme` property - -These changes are explained in more detail below, with examples for easy reference. - -### Capitalize Chain Names - -In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. - -=== "v0.x" - - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - ethereum: 'INSERT_ETH_RPC_URL', - solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` -=== "v1.x" - - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - Ethereum: 'INSERT_ETH_RPC_URL', - Solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` - -You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. - -### Rename `env` to `network` - -The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. - -=== "v0.x" - - ```typescript - const config: WormholeConnectConfig = { - env: 'testnet', - }; - ``` -=== "v1.x" + ```typescript + const config: WormholeConnectConfig = { + env: 'testnet', + }; + ``` +=== "v1.x" ```typescript const config: WormholeConnectConfig = { @@ -1164,7 +1215,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -1555,2394 +1606,2127 @@ wormholeConnectHosted(container, { In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect Tutorials -description: Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -categories: Connect, Transfer ---- - -# Connect - -Wormhole Connect makes it simple to link your application to multiple blockchain ecosystems. These tutorials will teach you how to integrate Connect into your projects, streamline cross-chain interactions, simplify user onboarding, and deliver a smoother overall experience. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Integrate Connect into a React DApp** - - --- - - Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - - [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) - -
- -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Connect** - - --- - - Get deeper insights into setting up and customizing Wormhole Connect. Explore advanced guides, best practices, and configuration tips to streamline your cross-chain integrations. - - [:custom-arrow: Learn more](/docs/build/transfers/connect/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- -title: Integrate Connect into a React DApp Tutorial -description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +title: Features +description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. categories: Connect, Transfer --- -# Integrate Connect into a React DApp - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} - -## Introduction - -In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. - -While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. - -## Prerequisites - -To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. -Before starting this tutorial, ensure you have the following: - -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use -- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} -- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees - -## Set Up Connect for Sui Transfers - -### Create a React Project - -Start by setting up your React app: - -1. Open your terminal and run the following command to create a new React app: - - ```bash - npx create-react-app connect-tutorial - ``` - -2. Navigate into the project directory: - - ```bash - cd connect-tutorial - ``` - -### Install Wormhole Connect - -Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: - -```bash -npm install @wormhole-foundation/wormhole-connect -``` - -### Integrate Connect into the Application - -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: - -=== "JavaScript" - - ```js - import logo from './logo.svg'; - import './App.css'; - import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - - const config = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], - }; - - function App() { - return ; - } - - export default App; - ``` - -=== "TypeScript" - - ```ts - import './App.css'; - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - } from '@wormhole-foundation/wormhole-connect'; - - function App() { - const config: WormholeConnectConfig = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], - - ui: { - title: 'SUI Connect TS Demo', - }, - }; - - const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - }; - - return ; - } - - export default App; - ``` - -- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment -- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche - -### Customize Wormhole Connect - -To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/build/transfers/connect/configuration/#introduction){target=\_blank}. - -### Run the Application - -Make sure you’re in the root directory of your React app, and run the following command to start the application: - -```bash -npm start -``` - -Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. - -## Transfer Tokens from Sui to Fuji - -Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. - -To transfer tokens from Sui to Fuji in the Wormhole Connect interface: - -1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer -2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network -3. Enter the amount of SUI tokens you wish to transfer - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) - -4. Choose to view other routes - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) - -5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) - - !!! note - It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) - -6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) - -7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) - -Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. - -## Claim Tokens on Fuji - -After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. - -![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) - -Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. - -![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) - -## Resources - -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. - -## Conclusion - -In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. - -By following these steps, you've learned how to: - -- Set up a React project tailored for cross-chain transfers -- Install and configure Wormhole Connect to support multiple blockchains -- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers -- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks - -With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. ---- END CONTENT --- - -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +## Feature Support Matrix {: #feature-support-matrix} -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +*Scroll down for details about each column.* -## Consistency Level +| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | +|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| +| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | +| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | +| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | +| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | +| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | +| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | +| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | +| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | +| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | +| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | +| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | +| Base | ✅ | ✅ | ✅ | ✅ | ✅ | +| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | +| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | +| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | +| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +## Feature Explanation {: #feature-explanation} -## Delivery Provider +### Token Bridge {: #token-bridge} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. -## Emitter +This route appears if both of the following conditions are satisfied: -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + - Both the origin and destination chains support Token Bridge + - No non-Token Bridge routes are available for the selected token -## Finality +### Token Bridge Relayer {: #token-bridge-relayer} -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. -## Guardian +Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +This route appears if all of the following conditions are satisfied: -## Guardian Network +- Both the origin and destination chains support Token Bridge +- Both the origin and destination chains support Token Bridge relayer +- No non-Token Bridge routes are available for the selected token +- The relayer supports the selected token on the origin chain -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +### Circle CCTP {: #circle-cctp} -## Guardian Set +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +This route appears if all of the following conditions are satisfied: -## Heartbeat +- Both the origin and destination chains support Circle CCTP +- The selected token is native Circle-issued USDC -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +### ETH Bridge {: #eth-bridge} -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. -## Observation +This route appears if all of the following conditions are satisfied: -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +- Both the origin and destination chains support the ETH Bridge +- The selected token is native ETH, wstETH, or canonical wETH -## Relayer +### Gas Drop Off {: #gas-drop-off} -A relayer is any process that delivers VAAs to a destination. +A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. -## Sequence +This route appears if all of the following conditions are satisfied: -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +- Both the origin and destination chains support gas drop off +- An automatic route is selected +- The relayer accepts the selected token to swap into the gas token +--- END CONTENT --- -## Spy +## Basics Concepts [shared: true] -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -## VAA +--- -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +## List of shared concept pages: -## Validator -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Infrastructure Components - -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. - -## Get Started - -Start here for an overview of Wormhole architecture components and security mechanisms: - -
- -- :octicons-book-16:{ .lg .middle } **Architecture Overview** - - --- - - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. - - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) - -- :octicons-book-16:{ .lg .middle } **Security** +# Wormhole Use Cases - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Cross-Chain Swaps and Liquidity Aggregation - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Enable seamless swaps between chains with real-time liquidity routing.
+
-## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: - -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] - -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Messaging Components** +🛠 **Wormhole products used:** - --- +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** - --- +
+
- Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +## Borrowing and Lending Across Chains - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Let users borrow assets on one chain using collateral from another.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- - -# Architecture +
-## Overview +🛠 **Wormhole products used:** -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +
+
-1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +
+
- - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +## Real-Time Price Feeds and Trading Strategies -## On-Chain Components +Fetch price feeds across multiple chains for DeFi applications. -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +
+
-## Off-Chain Components +🛠 **Wormhole products used:** -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -## Next Steps +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** - --- +
+
- Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +## Asset Movement Between Bitcoin and Other Chains - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable direct BTC transfers without wrapped assets. -- :octicons-tools-16:{ .lg .middle } **Core Messaging** +
+
- --- +🛠 **Wormhole products used:** - Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank}
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- +
-# Core Contracts +
+
-## Introduction +## Decentralized Social Platforms -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +Enable seamless communication and asset transfer across decentralized social networks. -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +
+
-## Key Functions +🛠 **Wormhole products used:** -Key functions of the Wormhole Core Contract include the following: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} -## How the Core Contract Works +
+
-The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -The following describes the role of the Wormhole Core Contract in message transfers: +
+
-1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +## Memecoin Launchpads -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. -### Message Submission +
+
-You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +🛠 **Wormhole products used:** -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -### Message Reception +
+
-When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -## Multicast +
+
-Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +## Cross-Chain Perpetuals -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +
+
-Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +🛠 **Wormhole products used:** -## Next Steps +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences -
+🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** +
+
- --- - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +
+
- [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +## Gas Abstraction -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - --- +
+
- This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +🛠 **Wormhole products used:** - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments + +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ ---- BEGIN CONTENT --- ---- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics ---- -## Guardian +
+
-Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +## Bridging Intent Library -Guardians fulfill their role in the messaging protocol as follows: +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state +
+
-Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -The Guardian Network is designed to help Wormhole deliver on five key principles: +
+
-- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -The following sections explore each principle in detail. +
+
-### Decentralization +## Multichain Prediction Markets -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. -Two common approaches to decentralization have notable limitations: +
+
-- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +🛠 **Wormhole products used:** -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -To answer that, consider these key constraints and design decisions: +
+
-- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +
+
-### Modularity +## Cross-Chain Payment Widgets -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -### Chain Agnosticism +
+
-Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +🛠 **Wormhole products used:** -### Scalability +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +
+
-Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -### Upgradeable +
+
-Wormhole is designed to adapt and evolve in the following ways: +## Oracle Networks -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +
+
-## Next Steps +🛠 **Wormhole products used:** -
+- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -- :octicons-book-16:{ .lg .middle } **Relayers** +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - --- +
+
- Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +
+
-- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +## Cross-Chain Staking - --- +Enable users to stake assets on one chain while earning rewards or securing networks on another. - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +
+
- [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +🛠 **Wormhole products used:** + +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks + +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -# Relayers +# Glossary -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +## Chain ID -There are three primary types of relayers discussed: +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Consistency Level -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -## Fundamentals +## Delivery Provider -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +## Emitter -Key characteristics of VAAs include: +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -- Public emission from the Guardian Network +## Finality -- Authentication through signatures from the Guardian Network +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -- Verifiability by any entity or any Wormhole Core Contract +## Guardian -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -Keep in mind the following security considerations around relayers: +## Guardian Network -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly +## Guardian Set -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Client-Side Relaying +## Heartbeat -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -### Key Features +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs +## Observation -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -### Implementation +## Relayer -Users themselves carry out the three steps of the cross-chain process: +A relayer is any process that delivers VAAs to a destination. -1. Perform an action on chain A +## Sequence -2. Retrieve the resulting VAA from the Guardian Network +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -3. Perform an action on chain B using the VAA +## Spy -### Considerations +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +--- BEGIN CONTENT --- +--- +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +categories: Basics +--- + +# Get Started with Core Contracts + +## Introduction + +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. + +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. + +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. + +## Prerequisites -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +To interact with the Wormhole Core Contract, you'll need the following: -- Users must sign all required transactions with their own wallet +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -- Users must have funds to pay the transaction fees on every chain involved +## How to Interact with Core Contracts -- The user experience may be cumbersome due to the manual steps involved +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -## Custom Relayers +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). +### Sending Messages -### Key Features +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs +=== "EVM" -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ??? interface "Parameters" -### Implementation + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + ??? interface "Returns" -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -## Wormhole Relayers + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -### Key Features +// Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -### Implementation +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -The Wormhole relayer integration involves two key steps: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +=== "Solana" -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -### Considerations + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. + ??? interface "Parameters" -- All computations are performed on-chain + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- Potentially less gas-efficient compared to custom relayers + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- Support may not be available for all chains + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -## Next Steps + ??? child "Type `PostMessage<'info>`" -
+ ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -- :octicons-book-16:{ .lg .middle } **Spy** + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - --- + --- - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `batch_id` ++"u32"++ + + An identifier for the message batch. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. - --- + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - --- + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -# Spy +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. +### Receiving Messages -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. +The way a message is received and handled depends on the environment. -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. +=== "EVM" -## Key Features + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Integrator Use Case + ??? interface "Parameters" -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ??? interface "Returns" -## Observable Message Categories + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -A Spy can access the following categories of messages shared over the gossip protocol: + ??? child "Struct `VM`" -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status + ??? interface "Example" - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## Additional Resources + // Perform safety checks here -
+ // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + // Your custom application logic here +} + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +=== "Solana" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + Retrieve the raw message data: - --- + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. + ??? interface "Example" - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +#### Validating the Emitter - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -
+Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Next Steps +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -
+This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - --- +await tx.wait(); +``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +#### Additional Checks - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- :octicons-code-16:{ .lg .middle } **Use Queries** +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - --- +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +## Source Code References - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +# Wormhole Relayer -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +## Introduction -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +## Get Started with the Wormhole Relayer -## VAA Format +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -The basic VAA consists of header and body components described as follows: +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- Where each `signature` is: +### Wormhole Relayer Interfaces - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Interact with the Wormhole Relayer -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -## Consistency and Finality +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +Your initial set up should resemble the following: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Signatures +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +contract Example { + IWormholeRelayer public wormholeRelayer; -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} ``` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Be aware of the following considerations when working with attestations: +### Send a Message -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -### Token Transfer with Message +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +### Receive a Message -### Governance +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -#### Action Structure +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +## Delivery Guarantees -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -#### Actions +## Delivery Statuses -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Lifetime of a Message +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Other Considerations -## Next Steps +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -
+- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -- :octicons-book-16:{ .lg .middle } **Guardians** +## Track the Progress of Messages with the Wormhole CLI - --- +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +=== "Mainnet" - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +=== "Testnet" - --- + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +## Step-by-Step Tutorial -
+For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# Introduction to Wormhole - -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +# Products -## What Problems Does Wormhole Solve? +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Critical problems Wormhole addresses include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## Transfer Products -## What Does Wormhole Offer? +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +
-## What Isn't Wormhole? +::spantable:: -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -## Use Cases of Wormhole +::end-spantable:: -Consider the following examples of potential applications enabled by Wormhole: +
-- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -## Explore +## Real-time Data -Discover more about the Wormhole ecosystem, components, and protocols: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +## Multichain Governance -## Demos +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# Architecture - +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -!!! note - Wormhole Integration Complete? +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Supported Blockchains + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Wormhole supports a growing number of blockchains. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - - -
+## On-Chain Components -### EVM +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Off-Chain Components -### SVM +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Core Contracts** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. -### Move VM + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -### Sui Move VM + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Security +# Core Contracts -## Core Security Assumptions +## Introduction -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -In summary: +## Key Functions -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Key functions of the Wormhole Core Contract include the following: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -## Guardian Network +## How the Core Contract Works -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -### Governance +The following describes the role of the Wormhole Core Contract in message transfers: -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +### Message Submission -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -Via governance, the Guardians can: +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Message Reception -## Monitoring +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +## Multicast -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -Guardians monitor: +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -## Asset Layer Protections +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +## Next Steps -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +
-In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -## Open Source + --- -Wormhole builds in the open and is always open source. + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -## Audits +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + --- -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -## Bug Bounties +
+--- END CONTENT --- -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Guardian -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +Guardians fulfill their role in the messaging protocol as follows: -## Learn More +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- +## Guardian Network -# Get Started with Core Contracts +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Introduction +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +The following sections explore each principle in detail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +### Decentralization -## Prerequisites +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -To interact with the Wormhole Core Contract, you'll need the following: +Two common approaches to decentralization have notable limitations: -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -## How to Interact with Core Contracts +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +To answer that, consider these key constraints and design decisions: -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -### Sending Messages +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +### Modularity -=== "EVM" +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +### Chain Agnosticism + +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +### Scalability - ??? interface "Parameters" +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +### Upgradeable - --- +Wormhole is designed to adapt and evolve in the following ways: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - ??? interface "Returns" +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Next Steps - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +
-// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +- :octicons-book-16:{ .lg .middle } **Relayers** -// Check fee and send parameters + --- -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -4376,245 +4160,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -4798,4 +4428,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index dde06b6f6..6198b97e1 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -13,316 +13,236 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/governance/ +Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ --- BEGIN CONTENT --- --- -title: Learn about MultiGov -description: Explore the MultiGov documentation for a comprehensive guide covering architecture, deployment, upgrading, integration, and FAQs. +title: MultiGov Guides +description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. categories: MultiGov --- -# MultiGov +# Cross-Chain treasury management proposal -Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. Get an introduction to the core concepts, explore how the system's components work together, and find answers to common questions to help you navigate the platform effectively. +This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. -## Get Started +## Create a Proposal -
+The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. -- :octicons-book-16:{ .lg .middle } **Overview** +In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. - --- +Key actions: + +- Define the proposal targets (two transactions to the Message Dispatcher) +- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) +- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum +- Finally, we submit the proposal to the `HubGovernor` contract + +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Prepare proposal details +address[] memory targets = new address[](2); +targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; +targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; +uint256[] memory values = new uint256[](2); +values[0] = 0; +values[1] = 0; +bytes[] memory calldatas = new bytes[](2); +// Prepare message for Optimism to mint 10 W tokens +// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) +calldatas[0] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + OPTIMISM_WORMHOLE_CHAIN_ID, + [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], + [uint256(10 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +// Prepare message for Arbitrum to receive 15 ETH +calldatas[1] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + ARBITRUM_WORMHOLE_CHAIN_ID, + [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], + [uint256(15 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; +// Create the proposal +uint256 proposalId = governor.propose( + targets, values, calldatas, description +) +``` - Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. +??? interface "Parameters" - [:custom-arrow: Take a first glance at MultiGov](/docs/learn/governance/overview/) + `GOVERNOR_ADDRESS` ++"address"++ -- :octicons-book-16:{ .lg .middle } **Architecture** + The address of the `HubGovernor` contract on Ethereum Mainnet. --- - Discover MultiGov's hub-and-spoke architecture, enabling EVM and Solana cross-chain governance through coordinated decision-making. - - [:custom-arrow: Learn about MultiGov architecture](/docs/products/multigov/concepts/architecture/) + `targets` ++"address[]"++ -- :octicons-question-16:{ .lg .middle } **Theoretical FAQs** + An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. --- - Find answers to common theoretical questions about MultiGov. - - [:custom-arrow: Find the answer to your theoretical questions](/docs/products/multigov/faqs/) + `values` ++"uint256[]"++ -
+ An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. -## Next Steps + --- -
+ `calldatas` ++"bytes[]"++ -- :octicons-checklist-16:{ .lg .middle } **Begin the MultiGov Integration Process** + The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. --- - Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. + `description` ++"string"++ - [:custom-arrow: Start the integration process now](/docs/build/multigov/) + A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains** +??? interface "Returns" - --- + `proposalId` ++"uint256"++ - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. + The ID of the newly created proposal on the hub chain. - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) +## Vote on the Proposal via Spoke -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** +Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. - --- +Key actions: - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. +- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain +- Cast a vote in support of the proposal - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) +```solidity +// Connect to the SpokeVoteAggregator contract of the desired chain +SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); +// Cast a vote +uint8 support = 1; // 1 for supporting, 0 for opposing +uint256 weight = voteAggregator.castVote(proposalId, support); +``` -- :octicons-code-square-16:{ .lg .middle } **Tutorials** +??? interface "Parameters" - --- + `VOTE_AGGREGATOR_ADDRESS` ++"address"++ - Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. + The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). - [:custom-arrow: Create MultiGov solutions](/docs/tutorials/multigov/) + --- -- :octicons-question-16:{ .lg .middle } **Technical FAQs** + `proposalId` ++"uint256"++ + + The ID of the proposal created on the hub chain, which is being voted on. --- - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. + `support` ++"uint8"++ - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) + The vote being cast (`1` for supporting the proposal, `0` for opposing). -
---- END CONTENT --- +??? interface "Returns" -Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: MultiGov Architecture -description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. -categories: MultiGov ---- + `weight` ++"uint256"++ -# MultiGov Architecture + The weight of the vote, determined by the voter’s token holdings on the spoke chain. -MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. +## Vote Aggregation -## Key Components +In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. -### Hub Chain Contracts +Key actions: -The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. +- Aggregate votes from different chains and submit them to the hub chain for tallying - - **`HubGovernor`** - central governance contract managing proposals and vote tallying - - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` - - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains - - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed - - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals - - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible +```solidity +// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) +hubVotePool.crossChainVote(queryResponseRaw, signatures); +``` -### Spoke Chains Contracts +??? interface "Parameters" -Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. + `queryResponseRaw` ++"bytes"++ - - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub - - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub - - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters - - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury + The raw vote data from the spoke chains. -### Spoke Solana Staking Program + --- -The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. + `signatures` ++"bytes"++ -The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: + Cryptographic signatures that verify the validity of the votes from the spoke chains. - - **`GlobalConfig`** - global program configuration - - **`StakeAccountMetadata`** - stores user's staking information - - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts - - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens - - **`CheckpointData`** - tracks delegation history - - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain - - **`GuardianSignatures`** - stores guardian signatures for message verification - - **`ProposalData`** - stores data about a specific proposal, including votes and start time - - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal - - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol - - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution - - **`VestingBalance`** - stores total vesting balance and related staking information of a vester - - **`VestingConfig`** - defines vesting configuration, including mint and admin details - - **`Vesting`** - represents individual vesting allocations with maturation data - - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows +## Execute Proposal and Dispatch Cross-Chain Messages -Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. +After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. -## System Workflow +Key actions: -The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. +- Execute the proposal after the voting period ends and the proposal passes +- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. -### EVM Governance Workflow +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Standard timelock execution +governor.execute(targets, values, calldatas, descriptionHash); +``` -The EVM-based MultiGov workflow follows these steps: +??? interface "Parameters" -1. **Proposal creation**: - 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method - 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold -2. **Proposal metadata distribution**: - 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` - 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details -3. **Voting process**: - 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` - 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole - 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution - 3. After the timelock delay, the proposal can be executed on the hub chain - 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains - 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` + `governor` ++"HubGovernor"++ -### Solana Governance Workflow + The `HubGovernor` contract instance. -The Solana-based MultiGov workflow follows these steps: + --- -1. **Proposal creation**: - 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold - 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function - 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution + `targets` ++"address[]"++ -2. **Proposal metadata distribution**: - 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** - 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program - 3. The proposal data is verified to ensure it matches the expected format - 4. Guardian signatures are posted using the `PostSignatures` instruction - 5. Once validated, the proposal is stored on-chain + An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). -3. **Voting process**: - 1. Users vote on proposals stored in the `ProposalData` account on Solana - 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) - 3. Eligibility and vote weight are verified using historical voter checkpoint data - 4. A **Query Wormhole** request retrieves vote data from a Solana PDA - 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification - 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision + --- -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution - 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain - 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana - 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions + `values` ++"uint256[]"++ -## Cross-Chain Communication + An array of values (in Wei) associated with each transaction (both are zero in this case). -MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. + --- -## Security Measures + `calldatas` ++"bytes[]"++ -- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting - - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions -- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review -- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol + The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). -## Detailed Architecture Diagram + --- -This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. + `descriptionHash` ++"bytes32"++ - -![detailed multigov architecture diagram](/docs/images/learn/governance/multigov-detailed.webp) + A hash of the proposal’s description, used to verify the proposal before execution. + +??? interface "Returns" + + No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. + +Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ ---- BEGIN CONTENT --- ---- -title: MultiGov Theoretical FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -categories: MultiGov ---- - -# FAQs - -## General Questions - -### What is MultiGov? - -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. - -### How does MultiGov differ from traditional DAO governance? - -Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. - -### What are the main components of MultiGov? - -The main components of MultiGov include: - -- **Hub chain** - central coordination point for governance activities -- **Spoke chains** - additional chains where token holders can participate in governance -- **Wormhole integration** - enables secure cross-chain message passing -- **Governance token** - allows holders to participate in governance across all integrated chains ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/governance/overview/ ---- BEGIN CONTENT --- ---- -title: MultiGov Overview -description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -categories: MultiGov ---- - -# MultiGov: Cross-Chain Governance with Wormhole - -## Overview - -### What Is MultiGov and Why Is It Important? - -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. - -MultiGov is important because it: - -- **Increases participation** by allowing token holders from multiple chains to engage in governance -- **Enhances security** by leveraging Wormhole's robust cross-chain communication -- **Improves scalability** by integrating any chain supported by Wormhole -- **Enables unified governance** and coordinated decision-making across multiple networks - -### Key Features - -- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains -- **Cross-chain voting** - token holders on any integrated chain can cast votes -- **Vote aggregation** - votes from all chains are collected and tallied on the hub -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Wormhole integration** - secure and reliable cross-chain communication -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain - -### High-Level Architecture Diagram - -The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. - -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. - - -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/learn/governance/multigov-high-level.webp) ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/multigov/ +Doc-Content: https://wormhole.com/docs/..build/multigov/ --- BEGIN CONTENT --- --- title: Getting Started with MultiGov @@ -410,132 +330,411 @@ Take the following steps to get started with a MultiGov integration:
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/..learn/governance/overview/ --- BEGIN CONTENT --- --- -title: Deploy MultiGov on EVM Chains -description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +title: MultiGov Overview +description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. categories: MultiGov --- -# Deploy MultiGov on EVM Chains +# MultiGov: Cross-Chain Governance with Wormhole -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/build/multigov/){target=\_blank}. +## Overview -Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. +### What Is MultiGov and Why Is It Important? -## Prerequisites +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. -To interact with MultiGov, you'll need the following: +MultiGov is important because it: -- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} -- Install [Git](https://git-scm.com/downloads){target=\_blank} -- Clone the repository: - ```bash - git clone https://github.com/wormhole-foundation/multigov - cd evm # for evm testing/deploying - ``` +- **Increases participation** by allowing token holders from multiple chains to engage in governance +- **Enhances security** by leveraging Wormhole's robust cross-chain communication +- **Improves scalability** by integrating any chain supported by Wormhole +- **Enables unified governance** and coordinated decision-making across multiple networks -## Development Setup +### Key Features -For developers looking to set up a local MultiGov environment: +- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains +- **Cross-chain voting** - token holders on any integrated chain can cast votes +- **Vote aggregation** - votes from all chains are collected and tallied on the hub +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Wormhole integration** - secure and reliable cross-chain communication +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain -1. Install dependencies: - ```bash - forge install - ``` +### High-Level Architecture Diagram -2. Set up environment variables: - ```bash - cp .env.example .env - ``` +The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. - Edit `.env` with your specific [configuration](#configuration){target=\_blank} +For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. -3. Compile contracts: - ```bash - forge build - ``` + +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) +--- END CONTENT --- -4. Deploy contracts (example for Sepolia testnet): +Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: MultiGov Architecture +description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. +categories: MultiGov +--- - For hub chains: - ```bash - forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast - ``` +# MultiGov Architecture - For spoke chains (e.g., Optimism Sepolia): - ```bash - forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast - ``` +MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. -## Configuration +## Key Components -When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: +### Hub Chain Contracts -### Hub Governor Key Parameters +The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. -- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day -- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal -- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful -- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day + - **`HubGovernor`** - central governance contract managing proposals and vote tallying + - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` + - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains + - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed + - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals + - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible - !!! note - This helps mitigate cross-chain double voting. +### Spoke Chains Contracts -### Hub Proposal Extender Key Parameters +Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. -- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours -- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour + - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub + - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub + - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters + - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury -### Spoke Vote Aggregator Key Parameters +### Spoke Solana Staking Program -- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day +The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. - !!! note - This is crucial for mitigating cross-chain double voting +The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: -### Hub Evm Spoke Vote Aggregator Key Parameters + - **`GlobalConfig`** - global program configuration + - **`StakeAccountMetadata`** - stores user's staking information + - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts + - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens + - **`CheckpointData`** - tracks delegation history + - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain + - **`GuardianSignatures`** - stores guardian signatures for message verification + - **`ProposalData`** - stores data about a specific proposal, including votes and start time + - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal + - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol + - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution + - **`VestingBalance`** - stores total vesting balance and related staking information of a vester + - **`VestingConfig`** - defines vesting configuration, including mint and admin details + - **`Vesting`** - represents individual vesting allocations with maturation data + - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows -- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes +Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. -### Updateable Governance Parameters +## System Workflow -The following key parameters can be updated through governance proposals: +The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. -- `votingDelay` - delay before voting starts (in seconds) -- `votingPeriod` - duration of the voting period (in seconds) -- `proposalThreshold` - threshold for creating proposals (in tokens) -- `quorum` - number of votes required for quorum -- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) -- `voteWeightWindow` - window for vote weight checkpoints (in seconds) -- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time +### EVM Governance Workflow -These parameters can be queried using their respective getter functions on the applicable contract. +The EVM-based MultiGov workflow follows these steps: -To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. ---- END CONTENT --- +1. **Proposal creation**: + 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method + 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold +2. **Proposal metadata distribution**: + 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` + 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details +3. **Voting process**: + 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` + 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole + 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution + 3. After the timelock delay, the proposal can be executed on the hub chain + 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains + 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ ---- BEGIN CONTENT --- ---- -title: MultiGov Deployment to Solana -description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. -categories: MultiGov ---- +### Solana Governance Workflow -# Deploy MultiGov on Solana +The Solana-based MultiGov workflow follows these steps: -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. +1. **Proposal creation**: + 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold + 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function + 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution -Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. +2. **Proposal metadata distribution**: + 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** + 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program + 3. The proposal data is verified to ensure it matches the expected format + 4. Guardian signatures are posted using the `PostSignatures` instruction + 5. Once validated, the proposal is stored on-chain -## Prerequisites +3. **Voting process**: + 1. Users vote on proposals stored in the `ProposalData` account on Solana + 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) + 3. Eligibility and vote weight are verified using historical voter checkpoint data + 4. A **Query Wormhole** request retrieves vote data from a Solana PDA + 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification + 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision -To deploy MultiGov on Solana, ensure you have the following installed: +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution + 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain + 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana + 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions - - Install [Git](https://git-scm.com/downloads){target=\_blank} - - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** +## Cross-Chain Communication + +MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. + +## Security Measures + +- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting + - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions +- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review +- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol + +## Detailed Architecture Diagram + +This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. + + +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ +--- BEGIN CONTENT --- +--- +title: MultiGov FAQs +description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +categories: MultiGov +--- + +# FAQs + +## What is MultiGov? + +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. + +## How does MultiGov ensure security in cross-chain communication? + +MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: + +- Message origin verification to prevent unauthorized governance actions +- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states +- Authorized participant validation to maintain the integrity of the governance process +- Replay attack prevention by tracking executed messages + +## Can MultiGov integrate with any blockchain? + +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. + +## How are votes aggregated across different chains? + +Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. + +## Can governance upgrade from a single chain to MultiGov? + +Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. + +## How can I create a proposal in MultiGov? + +Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. + +## How do I vote on a proposal if I hold tokens on a spoke chain? + +You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. + +## How are approved proposals executed across multiple chains? + +When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. + +## What are the requirements for using MultiGov? + +To use MultiGov, your DAO must meet the following requirements: + +- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance +- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature + +## What do I need to set up MultiGov for my project? + +Get started by filling out the form below: + +https://www.tally.xyz/get-started + +Tally will reach out to help get your DAO set up with MultiGov. + +To set up testing MultiGov for your DAO, you'll need: + +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed +- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) +- Modify and deploy the hub and spoke contracts using the provided scripts +- Set up the necessary environment variables and configurations + +## Can MultiGov be used with non-EVM chains? + +The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. + +## How can I customize voting parameters in MultiGov? + +Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. + +Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. + +## How does MultiGov handle potential network issues or temporary chain unavailability? + +MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: + +1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable +2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems +3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through +4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline + +However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. + +## How does MultiGov differ from traditional DAO governance? + +Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. + +## What are the main components of MultiGov? + +The main components of MultiGov include: + +- **Hub chain** - central coordination point for governance activities +- **Spoke chains** - additional chains where token holders can participate in governance +- **Wormhole integration** - enables secure cross-chain message passing +- **Governance token** - allows holders to participate in governance across all integrated chains +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ +--- BEGIN CONTENT --- +--- +title: Deploy MultiGov on EVM Chains +description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +categories: MultiGov +--- + +# Deploy MultiGov on EVM Chains + +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. + +Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. + +## Prerequisites + +To interact with MultiGov, you'll need the following: + +- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} +- Install [Git](https://git-scm.com/downloads){target=\_blank} +- Clone the repository: + ```bash + git clone https://github.com/wormhole-foundation/multigov + cd evm # for evm testing/deploying + ``` + +## Development Setup + +For developers looking to set up a local MultiGov environment: + +1. Install dependencies: + ```bash + forge install + ``` + +2. Set up environment variables: + ```bash + cp .env.example .env + ``` + + Edit `.env` with your specific [configuration](#configuration){target=\_blank} + +3. Compile contracts: + ```bash + forge build + ``` + +4. Deploy contracts (example for Sepolia testnet): + + For hub chains: + ```bash + forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast + ``` + + For spoke chains (e.g., Optimism Sepolia): + ```bash + forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast + ``` + +## Configuration + +When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: + +### Hub Governor Key Parameters + +- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day +- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal +- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful +- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day + + !!! note + This helps mitigate cross-chain double voting. + +### Hub Proposal Extender Key Parameters + +- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours +- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour + +### Spoke Vote Aggregator Key Parameters + +- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day + + !!! note + This is crucial for mitigating cross-chain double voting + +### Hub Evm Spoke Vote Aggregator Key Parameters + +- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes + +### Updateable Governance Parameters + +The following key parameters can be updated through governance proposals: + +- `votingDelay` - delay before voting starts (in seconds) +- `votingPeriod` - duration of the voting period (in seconds) +- `proposalThreshold` - threshold for creating proposals (in tokens) +- `quorum` - number of votes required for quorum +- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) +- `voteWeightWindow` - window for vote weight checkpoints (in seconds) +- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time + +These parameters can be queried using their respective getter functions on the applicable contract. + +To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: MultiGov Deployment to Solana +description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. +categories: MultiGov +--- + +# Deploy MultiGov on Solana + +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. + +Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. + +## Prerequisites + +To deploy MultiGov on Solana, ensure you have the following installed: + + - Install [Git](https://git-scm.com/downloads){target=\_blank} + - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** - Install [Solana CLI](https://docs.anza.xyz/cli/install/){target=\_blank} **`v1.18.20`** - Install [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`v0.30.1`** - Install [Rust](https://www.rust-lang.org/tools/install){target=\_blank} **`v1.80.1`** @@ -706,125 +905,32 @@ When deploying MultiGov on Solana, several key parameters need to be set. Here a - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ --- BEGIN CONTENT --- --- -title: MultiGov Technical FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +title: Upgrading MultiGov on EVM +description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. categories: MultiGov --- -# FAQs +# Upgrade MultiGov Contracts on EVM Chains -## Technical Questions +MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. -### How does MultiGov ensure security in cross-chain communication? +## Key Considerations for Upgrades -MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: +- **`HubGovernor`**: + - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details -- Message origin verification to prevent unauthorized governance actions -- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states -- Authorized participant validation to maintain the integrity of the governance process -- Replay attack prevention by tracking executed messages +- **`HubVotePool`**: + - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` + - Requires re-registering all spokes on the new `HubVotePool` + - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` + - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` -### Can MultiGov integrate with any blockchain? - -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. - -### How are votes aggregated across different chains? - -Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. - -### Can governance upgrade from a single chain to MultiGov? - -Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. - -## Usage Questions - -### How can I create a proposal in MultiGov? - -Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. - -### How do I vote on a proposal if I hold tokens on a spoke chain? - -You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. - -### How are approved proposals executed across multiple chains? - -When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. - -## Implementation Questions - -### What are the requirements for using MultiGov? - -To use MultiGov, your DAO must meet the following requirements: - -- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance -- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature - -### What do I need to set up MultiGov for my project? - -Get started by filling out the form below: - -https://www.tally.xyz/get-started - -Tally will reach out to help get your DAO set up with MultiGov. - -To set up testing MultiGov for your DAO, you'll need: - -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed -- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) -- Modify and deploy the hub and spoke contracts using the provided scripts -- Set up the necessary environment variables and configurations - -### Can MultiGov be used with non-EVM chains? - -The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. - -### How can I customize voting parameters in MultiGov? - -Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. - -Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. - -### How does MultiGov handle potential network issues or temporary chain unavailability? - -MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: - -1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable -2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems -3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through -4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline - -However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ ---- BEGIN CONTENT --- ---- -title: Upgrading MultiGov on EVM -description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. -categories: MultiGov ---- - -# Upgrade MultiGov Contracts on EVM Chains - -MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. - -## Key Considerations for Upgrades - -- **`HubGovernor`**: - - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details - -- **`HubVotePool`**: - - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` - - Requires re-registering all spokes on the new `HubVotePool` - - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` - - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` - -- **`SpokeMessageExecutor`**: - - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern - - Stores critical parameters in `SpokeMessageExecutorStorage` +- **`SpokeMessageExecutor`**: + - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern + - Stores critical parameters in `SpokeMessageExecutorStorage` - **`HubEvmSpokeAggregateProposer`**: - Needs redeployment if `HubGovernor` changes @@ -940,288 +1046,304 @@ Follow these steps to upgrade the MultiGov Staking Program on Solana: ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tutorials/multigov/ +## Basics Concepts [shared: true] + +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. + +--- + +## List of shared concept pages: + + +## Full content for shared concepts: + +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Step-by-Step MultiGov Tutorials -description: Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. -categories: MultiGov +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +categories: Basics --- -# MultiGov +# Wormhole Use Cases -Welcome to the MultiGov tutorials section. In this section, you will find tutorials that walk you through the key steps of working with MultiGov, providing clear instructions to help you get started. As you explore, you'll gain a deeper understanding of MultiGov's features and functionality. +
+
-## Tutorials +## Cross-Chain Swaps and Liquidity Aggregation -
+Enable seamless swaps between chains with real-time liquidity routing. -- :octicons-repo-16:{ .lg .middle } **Cross-Chain Treasury Management Proposal** +
+
- --- +🛠 **Wormhole products used:** - Learn how to propose governance actions on a hub chain, gather votes from spoke chains, aggregate the results, and carry out the final decision. Following these steps, you’ll master end-to-end governance workflows spanning multiple networks. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - [:custom-arrow: Start building](/docs/products/multigov/tutorials/treasury-proposal/) +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank}
+
-## Additional Resources -
+
+
-- :octicons-book-16:{ .lg .middle } **Governance Fundamentals** +## Borrowing and Lending Across Chains - --- +Let users borrow assets on one chain using collateral from another. + +
+
+ +🛠 **Wormhole products used:** - Dive into Wormhole’s governance mechanisms. Understand how cross-chain governance works, proposal creation, voting, and execution. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - [:custom-arrow: Explore governance](/docs/learn/governance/) +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -- :octicons-tools-16:{ .lg .middle } **Implement MultiGov** +
+
- --- - Integrate MultiGov into your smart contracts. Access reference code, best practices, and guidance for deploying cross-chain governance systems. +
+
+## Real-Time Price Feeds and Trading Strategies - [:custom-arrow: Build with MultiGov](/docs/build/multigov/) +Fetch price feeds across multiple chains for DeFi applications.
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ ---- BEGIN CONTENT --- ---- -title: MultiGov Guides -description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. -categories: MultiGov ---- +🛠 **Wormhole products used:** -# Cross-Chain treasury management proposal +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Create a Proposal +
+
-The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. -In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. +
+
-Key actions: +## Asset Movement Between Bitcoin and Other Chains -- Define the proposal targets (two transactions to the Message Dispatcher) -- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) -- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum -- Finally, we submit the proposal to the `HubGovernor` contract +Enable direct BTC transfers without wrapped assets. -```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Prepare proposal details -address[] memory targets = new address[](2); -targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; -targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; -uint256[] memory values = new uint256[](2); -values[0] = 0; -values[1] = 0; -bytes[] memory calldatas = new bytes[](2); -// Prepare message for Optimism to mint 10 W tokens -// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) -calldatas[0] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - OPTIMISM_WORMHOLE_CHAIN_ID, - [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], - [uint256(10 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -// Prepare message for Arbitrum to receive 15 ETH -calldatas[1] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - ARBITRUM_WORMHOLE_CHAIN_ID, - [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], - [uint256(15 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; -// Create the proposal -uint256 proposalId = governor.propose( - targets, values, calldatas, description -) -``` +
+
-??? interface "Parameters" +🛠 **Wormhole products used:** - `GOVERNOR_ADDRESS` ++"address"++ +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - The address of the `HubGovernor` contract on Ethereum Mainnet. +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - --- +
+
- `targets` ++"address[]"++ +
+
- An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. +## Decentralized Social Platforms - --- +Enable seamless communication and asset transfer across decentralized social networks. - `values` ++"uint256[]"++ +
+
- An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - `calldatas` ++"bytes[]"++ +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. +
+
- --- - `description` ++"string"++ +
+
- A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. +## Memecoin Launchpads -??? interface "Returns" +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - `proposalId` ++"uint256"++ +
+
- The ID of the newly created proposal on the hub chain. +🛠 **Wormhole products used:** -## Vote on the Proposal via Spoke +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -Key actions: +
+
-- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain -- Cast a vote in support of the proposal -```solidity -// Connect to the SpokeVoteAggregator contract of the desired chain -SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); -// Cast a vote -uint8 support = 1; // 1 for supporting, 0 for opposing -uint256 weight = voteAggregator.castVote(proposalId, support); -``` +
+
-??? interface "Parameters" +## Cross-Chain Perpetuals - `VOTE_AGGREGATOR_ADDRESS` ++"address"++ +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). +
+
- --- +🛠 **Wormhole products used:** - `proposalId` ++"uint256"++ +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - The ID of the proposal created on the hub chain, which is being voted on. +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - --- +
+
- `support` ++"uint8"++ - The vote being cast (`1` for supporting the proposal, `0` for opposing). +
+
-??? interface "Returns" +## Gas Abstraction - `weight` ++"uint256"++ +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - The weight of the vote, determined by the voter’s token holdings on the spoke chain. +
+
-## Vote Aggregation +🛠 **Wormhole products used:** -In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments -Key actions: +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -- Aggregate votes from different chains and submit them to the hub chain for tallying +
+
-```solidity -// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) -hubVotePool.crossChainVote(queryResponseRaw, signatures); -``` -??? interface "Parameters" +
+
- `queryResponseRaw` ++"bytes"++ +## Bridging Intent Library - The raw vote data from the spoke chains. +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - --- +
+
- `signatures` ++"bytes"++ +🛠 **Wormhole products used:** - Cryptographic signatures that verify the validity of the votes from the spoke chains. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -## Execute Proposal and Dispatch Cross-Chain Messages +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. +
+
-Key actions: -- Execute the proposal after the voting period ends and the proposal passes -- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. +
+
-```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Standard timelock execution -governor.execute(targets, values, calldatas, descriptionHash); -``` +## Multichain Prediction Markets -??? interface "Parameters" +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - `governor` ++"HubGovernor"++ +
+
- The `HubGovernor` contract instance. +🛠 **Wormhole products used:** - --- +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - `targets` ++"address[]"++ +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). +
+
- --- - `values` ++"uint256[]"++ +
+
- An array of values (in Wei) associated with each transaction (both are zero in this case). +## Cross-Chain Payment Widgets - --- +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - `calldatas` ++"bytes[]"++ +
+
- The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). +🛠 **Wormhole products used:** - --- +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - `descriptionHash` ++"bytes32"++ +🔗 **Used in:** E-commerce, Web3 payments, and subscription models - A hash of the proposal’s description, used to verify the proposal before execution. +
+
-??? interface "Returns" - No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. +
+
-Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. ---- END CONTENT --- +## Oracle Networks -## Basics Concepts [shared: true] +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. +
+
---- +🛠 **Wormhole products used:** -## List of shared concept pages: +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +
+
-## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +
+
+ +## Cross-Chain Staking + +Enable users to stake assets on one chain while earning rewards or securing networks on another. + +
+
+ +🛠 **Wormhole products used:** + +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks + +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} + +
+
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- title: Glossary @@ -1298,2077 +1420,1666 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Infrastructure Components - -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +# Get Started with Core Contracts -## Get Started +## Introduction -Start here for an overview of Wormhole architecture components and security mechanisms: +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -
+While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- :octicons-book-16:{ .lg .middle } **Architecture Overview** +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - --- +## Prerequisites - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +To interact with the Wormhole Core Contract, you'll need the following: - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -- :octicons-book-16:{ .lg .middle } **Security** +## How to Interact with Core Contracts - --- +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - [:custom-arrow: Learn About Security](/docs/protocol/security/) +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -
+### Sending Messages -## Explore Components +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +=== "EVM" -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -## Next Steps + ??? interface "Parameters" -
+ `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -- :octicons-book-16:{ .lg .middle } **Messaging Components** + --- - --- + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers + --- - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** + ??? interface "Returns" - --- + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -
---- END CONTENT --- +// Check fee and send parameters -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -# Architecture +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -## Overview +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +=== "Solana" -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. - - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: - - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - -## On-Chain Components - -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract - -## Off-Chain Components - -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Core Contracts** - - --- - - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - -- :octicons-tools-16:{ .lg .middle } **Core Messaging** - - --- - - Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. - -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - -## Key Functions - -Key functions of the Wormhole Core Contract include the following: - -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - -## How the Core Contract Works - -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. - -The following describes the role of the Wormhole Core Contract in message transfers: - -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions - -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - -### Message Submission - -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page - -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. - -### Message Reception - -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - -## Multicast - -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. - -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. - -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. - -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - - --- - - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - - --- - - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ ---- BEGIN CONTENT --- ---- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics ---- - -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing - -The following sections explore each principle in detail. - -### Decentralization - -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. - -Two common approaches to decentralization have notable limitations: - -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment - -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. - -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? - -To answer that, consider these key constraints and design decisions: - -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants - -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. - -### Modularity - -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - -### Chain Agnosticism - -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - -### Scalability - -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - -### Upgradeable - -Wormhole is designed to adapt and evolve in the following ways: - -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Relayers** - - --- - - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - - --- - - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ ---- BEGIN CONTENT --- ---- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -categories: Basics ---- - -# Relayers - -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - -There are three primary types of relayers discussed: - -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - -## Fundamentals - -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - -Key characteristics of VAAs include: - -- Public emission from the Guardian Network - -- Authentication through signatures from the Guardian Network - -- Verifiability by any entity or any Wormhole Core Contract - -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - -Keep in mind the following security considerations around relayers: - -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks - -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain - -## Client-Side Relaying - -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. - -### Key Features - -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs - -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - -### Implementation - -Users themselves carry out the three steps of the cross-chain process: - -1. Perform an action on chain A - -2. Retrieve the resulting VAA from the Guardian Network - -3. Perform an action on chain B using the VAA - -### Considerations - -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - -- Users must sign all required transactions with their own wallet - -- Users must have funds to pay the transaction fees on every chain involved - -- The user experience may be cumbersome due to the manual steps involved - -## Custom Relayers - -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - -### Key Features - -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application - -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - -### Implementation - -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - -### Considerations - -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - -- Development work and hosting of relayers are required - -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - -- Relayers are responsible for availability, and adding dependencies for the cross-chain application - -## Wormhole Relayers - -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. - -### Key Features - -- **Lower operational costs** - no need to develop, host, or maintain individual relayers - -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface - -### Implementation - -The Wormhole relayer integration involves two key steps: - -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract - -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA - -### Considerations + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. + ??? interface "Parameters" -- All computations are performed on-chain + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- Potentially less gas-efficient compared to custom relayers + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- Support may not be available for all chains + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -## Next Steps + ??? child "Type `PostMessage<'info>`" -
+ ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -- :octicons-book-16:{ .lg .middle } **Spy** + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - --- + --- - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `batch_id` ++"u32"++ + + An identifier for the message batch. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. - --- + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - --- + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -# Spy +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. +### Receiving Messages -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. +The way a message is received and handled depends on the environment. -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. +=== "EVM" -## Key Features + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Integrator Use Case + ??? interface "Parameters" -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ??? interface "Returns" -## Observable Message Categories + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -A Spy can access the following categories of messages shared over the gossip protocol: + ??? child "Struct `VM`" -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status + ??? interface "Example" - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## Additional Resources + // Perform safety checks here -
+ // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + // Your custom application logic here +} + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +=== "Solana" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + Retrieve the raw message data: - --- + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. + ??? interface "Example" - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +#### Validating the Emitter - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -
+Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Next Steps +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -
+This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - --- +await tx.wait(); +``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +#### Additional Checks - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- :octicons-code-16:{ .lg .middle } **Use Queries** +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - --- +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +## Source Code References - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +# Wormhole Relayer -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +## Introduction -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +## Get Started with the Wormhole Relayer -## VAA Format +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -The basic VAA consists of header and body components described as follows: +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- Where each `signature` is: +### Wormhole Relayer Interfaces - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Interact with the Wormhole Relayer -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -## Consistency and Finality +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +Your initial set up should resemble the following: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Signatures +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +contract Example { + IWormholeRelayer public wormholeRelayer; -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} ``` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Be aware of the following considerations when working with attestations: +### Send a Message -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -### Token Transfer with Message +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +### Receive a Message -### Governance +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -#### Action Structure +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +## Delivery Guarantees -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -#### Actions +## Delivery Statuses -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Lifetime of a Message +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Other Considerations -## Next Steps +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -
+- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -- :octicons-book-16:{ .lg .middle } **Guardians** +## Track the Progress of Messages with the Wormhole CLI - --- +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +=== "Mainnet" - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +=== "Testnet" - --- + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +## Step-by-Step Tutorial -
+For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# Introduction to Wormhole - -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +# Products -## What Problems Does Wormhole Solve? +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Critical problems Wormhole addresses include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## Transfer Products -## What Does Wormhole Offer? +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +
-## What Isn't Wormhole? +::spantable:: -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -## Use Cases of Wormhole +::end-spantable:: -Consider the following examples of potential applications enabled by Wormhole: +
-- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -## Explore +## Real-time Data -Discover more about the Wormhole ecosystem, components, and protocols: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +## Multichain Governance -## Demos +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# Architecture - +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -!!! note - Wormhole Integration Complete? +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Supported Blockchains + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Wormhole supports a growing number of blockchains. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - - -
+## On-Chain Components -### EVM +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Off-Chain Components -### SVM +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Core Contracts** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. -### Move VM + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -### Sui Move VM + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Security +# Core Contracts -## Core Security Assumptions +## Introduction -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -In summary: +## Key Functions -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Key functions of the Wormhole Core Contract include the following: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -## Guardian Network +## How the Core Contract Works -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -### Governance +The following describes the role of the Wormhole Core Contract in message transfers: -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +### Message Submission -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -Via governance, the Guardians can: +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Message Reception -## Monitoring +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +## Multicast -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -Guardians monitor: +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -## Asset Layer Protections +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +## Next Steps -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +
-In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -## Open Source + --- -Wormhole builds in the open and is always open source. + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -## Audits +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + --- -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -## Bug Bounties +
+--- END CONTENT --- -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Guardian -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +Guardians fulfill their role in the messaging protocol as follows: -## Learn More +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- +## Guardian Network -# Get Started with Core Contracts +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Introduction +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +The following sections explore each principle in detail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +### Decentralization -## Prerequisites +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -To interact with the Wormhole Core Contract, you'll need the following: +Two common approaches to decentralization have notable limitations: -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -## How to Interact with Core Contracts +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +To answer that, consider these key constraints and design decisions: -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -### Sending Messages +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +### Modularity -=== "EVM" +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +### Chain Agnosticism + +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +### Scalability - ??? interface "Parameters" +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +### Upgradeable - --- +Wormhole is designed to adapt and evolve in the following ways: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - ??? interface "Returns" +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Next Steps - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +
-// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +- :octicons-book-16:{ .lg .middle } **Relayers** -// Check fee and send parameters + --- -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -3802,245 +3513,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -4224,4 +3781,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 2e45f92b0..2a9d6b5a6 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -13,1504 +13,1761 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/ +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ --- BEGIN CONTENT --- --- -title: A Quick Look at Native Token Transfers -description: This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. +title: Native Token Transfers (NTT) +description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. categories: NTT, Transfer --- # Native Token Transfers -## Get Started - -This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. - -
- -- :octicons-question-16:{ .lg .middle } **Overview** - - --- - - Dive into an introduction to NTT and discover what NTT is, what its key features are, and the available integration paths. - - [:custom-arrow: Learn more about NTT](/docs/learn/transfers/native-token-transfers/overview/) - -- :octicons-question-16:{ .lg .middle } **Architecture** - - --- - - Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. - - [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) - -- :octicons-book-16:{ .lg .middle } **Deployment Models** - - --- +Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. - The NTT framework offers two deployment models for different token management needs: the hub-and-spoke and burn-and-mint models. +Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. - [:custom-arrow: Check out the deployment models](/docs/learn/transfers/native-token-transfers/deployment/) +## Quickstart -- :octicons-shield-lock-16:{ .lg .middle } **Security** +If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - --- +The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: - Explore NTT's security measures, including the Global Accountant and governance strategies for seamless token safety. +[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] - [:custom-arrow: Review the security measures](/docs/learn/transfers/native-token-transfers/security/) +## Deploy NTTs with Launchpad -
+If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -## Next Steps +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. -Ready to dive in and start building? Check out the following resources to begin the deployment process and make the most of your deployment. +## Additional Resources
-- :octicons-rocket-16:{ .lg .middle } **Deploy NTT** +- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** --- - Explore detailed guides that walk you through the entire deployment process, from installing the NTT CLI to deploying NTT across supported chains. + The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - [:custom-arrow: Deploy now using the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/) + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) -- :octicons-checklist-16:{ .lg .middle } **Post Deployment Recommendations** +- :octicons-question-16:{ .lg .middle } **NTT FAQs** --- - Already deployed your NTT project? Check out these post deployment recommendations and integration demos to get the most out of your deployment. + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - [:custom-arrow: Get the most of out your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Architecture -description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +title: Native Token Transfers Installation +description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. categories: NTT, Transfer --- -## Introduction +# Install the Native Token Transfers CLI -The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. +In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. -For the technical implementations of the functions, refer to the [Managers and Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/){target=\_blank} page. +To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. -## System Components +
-The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. +## Install NTT CLI -### Managers +The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: -_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. +- Install [Bun](https://bun.sh/docs/installation){target=\_blank} -Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. +Follow these steps to install the NTT CLI: -A manager is responsible for: +1. Run the installation command in your terminal: -- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer -- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers - - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted - - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` - Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit +2. Verify the NTT CLI is installed: -- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed -- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility + ```bash + ntt --version + ``` -### Transceivers +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI -_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. +## Update NTT CLI -While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. +To update an existing NTT CLI installation, run the following command in your terminal: -Transceivers are entrusted with several responsibilities: +```bash +ntt update +``` -- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing -- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer -- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. -How it works: +For local development, you can update your CLI version from a specific branch or install from a local path. -1. The transceiver receives instructions from the manager to send messages across chains -2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred -3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain +To install from a specific branch, run: -![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) +```bash +ntt update --branch foo +``` -!!! note - [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` -#### Custom Transceivers +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. -The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. +## Where to Go Next -NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. +
-![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) -The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. +- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** -For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. + --- -## Lifecycle of a Message + Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) -### Transfer +- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** -The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. + --- -In both cases: + Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain -- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) -Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. +
+--- END CONTENT --- -### Rate Limit +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer +--- -Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. +# Native Token Transfers Post Deployment -- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error -- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): -Both chains emit events or logs when transfers are rate-limited or queued. +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment -### Send +## Manual Relaying for Solana Transfers -After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. -- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message -- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. +[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. -### Receive +## Where to Go Next -Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. +
-- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers -- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** -In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. + --- -### Mint or Unlock + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. -Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) -- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred -- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** -In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. + --- + + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. + + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/deployment/ +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ --- BEGIN CONTENT --- --- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. categories: NTT, Transfer --- -# Deployment Models - -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. - -## Hub-and-Spoke - -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. +# Managers and Transceivers -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. +## Managers -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain -## Burn-and-Mint + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) + ``` -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer -This model best suits new token deployments or projects willing to upgrade existing contracts. + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain ---- END CONTENT --- +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner + ``` -# Native Token Transfers +## Transceivers -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -## Introduction + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -## Key Features +## Lifecycle of a Message -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: +### EVM -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds +#### Transfer -## Integration Paths +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. +**Events** -### Native Token Transfers Framework +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); +``` -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. +#### Rate Limit -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. -### Token Bridge +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains +**Events** -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. +```ts +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); +``` -## Supported Token Standards +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/security/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Security -description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -categories: NTT, Transfer ---- +#### Send -# Security +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). -## Global Accountant +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. -The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. +**Events** -This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` -[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. +#### Receive -## Governance and Upgradeability +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. -Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. -The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. -- Adding or removing a transceiver address from the registry -- Setting the token contract address on a bridging contract -- Setting the Wormhole Core Contract address on a bridging contract -- Setting the registered bridging contract address on the token contract +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. -This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. ---- END CONTENT --- +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- +**Events** -# Native Token Transfers +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -## Quickstart +#### Mint or Unlock -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: +**Events** -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] +```ts +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); +``` -## Deploy NTTs with Launchpad +### Solana -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. +#### Transfer -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. -## Additional Resources +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -
+Depending on the mode and instruction, the following will be produced in the program logs: -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` - --- +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. +#### Rate Limit - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +If the transfer amount fits within the current capacity: - --- +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +If the transfer amount doesn't fit within the current capacity: - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -
---- END CONTENT --- +#### Send -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ ---- BEGIN CONTENT --- ---- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer ---- +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. -# NTT CLI Commands +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. -## Introduction +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. +The following will be produced in the program logs: -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](/docs/build/transfers/native-token-transfers/deployment-process/installation/#installation){target=\_blank} to set it up before proceeding. +```ts +Program log: Instruction: ReleaseOutbound +``` -## Table of Commands +#### Receive -The following table lists the available NTT CLI commands, descriptions, and examples. +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. -### General Commands +The following will be produced in the program logs: -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | - -### Configuration Commands - -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| - -### Solana Commands - -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| - -## Where to Go Next - -
- - -- :octicons-gear-16:{ .lg .middle } **Configure NTT** +```ts +Program log: Instruction: ReceiveMessage +``` - --- +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +The following will be produced in the program logs: - [:custom-arrow: Configure your NTT deployment](/docs/build/transfers/native-token-transfers/configuration/) +```ts +Program log: Instruction: Redeem +``` -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +#### Mint or Unlock - --- +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +Depending on the mode and instruction, the following will be produced in the program logs: -
+```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/ +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ --- BEGIN CONTENT --- --- -title: Native Token Transfers (NTT) - Configuration -description: This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +title: Native Token Transfers - Deployment Models +description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. categories: NTT, Transfer --- -# Configure Native Token Transfers (NTT) - -## Get Started - -This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +# Deployment Models -
+The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. -- :octicons-clock-16:{ .lg .middle } **Rate Limiting** +## Hub-and-Spoke - --- +The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - Discover options for configuring rate limits and how queueing effects transaction flow. +This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) +- **Hub chain** - tokens are locked when initiating a transfer +- **Spoke chains** - Equivalent tokens are minted on the destination chain -- :octicons-unlock-16:{ .lg .middle } **Access Control** +When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - --- +## Burn-and-Mint - Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. +The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) +This model best suits new token deployments or projects willing to upgrade existing contracts. -
+- **Source chain** - tokens are burned when initiating a transfer +- **Destination chain** - equivalent tokens are minted on the destination chain --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Access Control -description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +title: Native Token Transfers Overview +description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. categories: NTT, Transfer --- -## Owner and Pauser Roles - -Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). - -NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. - -- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused -- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts - -You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. - -```json -{ - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": true, // set to true to pause the contract - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - //... - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } -} -``` - -!!! note - While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. - -The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. +# Native Token Transfers -Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. ---- END CONTENT --- +!!!tip "Looking to deploy NTT?" + If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Rate Limiting -description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. -categories: NTT, Transfer ---- + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} ## Introduction -The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. - -If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. - -You can configure the following limits on every chain where NTT is deployed directly using the manager: - -- **Sending limit** - a single outbound limit for sending tokens from the chain -- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum - -Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. +Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. -## Update Rate Limits +The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. -To configure or update the sending and receiving rate limits, follow these steps: +## Key Features -1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts +Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: -2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed +- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens +- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience +- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk +- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts +- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains +- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted +- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner +- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols +- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - ```json - "limits": { - "outbound": "1000.000000000000000000", - "inbound": { - "Ethereum": "100.000000000000000000", - "Arbitrum": "50.000000000000000000" - } - } - ``` +## Integration Paths - - **`outbound`** - sets the maximum tokens allowed to leave the chain - - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains +Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. -3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain +### Native Token Transfers Framework - ```bash - ntt push - ``` +The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. -4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status +- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model +- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant +- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain +- **Token contracts** - native contracts owned by your protocol governance +- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - ```bash - ntt status - ``` +The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: -???- note "`deployment.json` example" - ```json - { - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": false, - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", - "transceivers": { - "threshold": 1, - "wormhole": { - "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - }, - "limits": { - "outbound": "184467440737.095516150000000000", - "inbound": { - "ArbitrumSepolia": "500.000000000000000000" - } - }, - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } - } - ``` +- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} +- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} -## Queuing Mechanism +### Token Bridge -When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: +The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. -- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer -- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain +- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract +- **Security** - preconfigured rate limiting and integrated Global Accountant +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} +- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process +- **Integration** - straightforward and permissionless method to deploy on multiple chains -Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. +!!! note + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. -## Cancel Flows +## Supported Token Standards -If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. +Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- -title: Native Token Transfers (NTT) - Deployment -description: This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. +title: Native Token Transfers Architecture +description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. categories: NTT, Transfer --- -# Deploy Native Token Transfers (NTT) +## Introduction -## Get Started +The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. -This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. -
+## System Components -- :octicons-download-16:{ .lg .middle } **Installation** +The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. - --- +### Managers - Prerequisites and commands for installing the NTT CLI and working with the NTT framework. +_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. - [:custom-arrow: Install the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/) +Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** +A manager is responsible for: - --- +- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer +- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers + - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted + - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded - Find information on preparing for NTT deployment to EVM, including an example NTT token repository. + Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) +- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed +- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** +### Transceivers - --- +_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. - Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. - [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) +Transceivers are entrusted with several responsibilities: -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing +- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer +- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) +How it works: -- :octicons-search-16:{ .lg .middle } **Post Deployment** +1. The transceiver receives instructions from the manager to send messages across chains +2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred +3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain - --- +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) - Learn how to best monitor and maintain your NTT deployment to get the most out of your Wormhole integration while providing security for users. +!!! note + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. - [:custom-arrow: Explore next steps](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) +#### Custom Transceivers -- :octicons-alert-16:{ .lg .middle } **Troubleshooting** +The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. - --- +NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. - Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) - [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) +The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. -
---- END CONTENT --- +For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers EVM Deployment -description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer ---- +## Lifecycle of a Message -# Native Token Transfers (NTT) EVM Development +The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. -## Deploy Your Token and Ensure Compatibility +### Transfer -If you still need to do so, deploy the token contract to the destination or spoke chains. +The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. -### Requirements for Token Deployment +In both cases: -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain +- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain -#### Burn-and-Mint Mode +Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: +### Rate Limit -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` +Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. +- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error +- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; +Both chains emit events or logs when transfers are rate-limited or queued. -interface INttToken { - /// @notice Error when the caller is not the minter. - /// @dev Selector 0x5fb5729e. - /// @param caller The caller of the function. - error CallerNotMinter(address caller); +### Send - /// @notice Error when the minter is the zero address. - /// @dev Selector 0x04a208c7. - error InvalidMinterZeroAddress(); +After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. - /// @notice Error when insufficient balance to burn the amount. - /// @dev Selector 0xcf479181. - /// @param balance The balance of the account. - /// @param amount The amount to burn. - error InsufficientBalance(uint256 balance, uint256 amount); +- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message +- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification - /// @notice The minter has been changed. - /// @dev Topic0 - /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. - /// @param newMinter The new minter. - event NewMinter(address previousMinter, address newMinter); +In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. - // NOTE: the `mint` method is not present in the standard ERC20 interface. - function mint(address account, uint256 amount) external; +### Receive - // NOTE: the `setMinter` method is not present in the standard ERC20 interface. - function setMinter(address newMinter) external; +Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. - // NOTE: NttTokens in `burn` mode require the `burn` method to be present. - // This method is not present in the standard ERC20 interface, but is - // found in the `ERC20Burnable` interface. - function burn(uint256 amount) external; -} - ``` +- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers +- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. +In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. -#### Hub-and-Spoke Mode +### Mint or Unlock -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. +Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers +- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred +- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. +--- END CONTENT --- -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/security/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Security +description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. +categories: NTT, Transfer +--- -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. +# Security -For more detailed information, see the [Deployment Models](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank} page. +## Global Accountant -### Key Differences Between Modes +The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. -## Deploy NTT +[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. -Create a new NTT project: +## Governance and Upgradeability -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` +Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. -Initialize a new `deployment.json` file specifying the network: +The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: -=== "Testnet" +- Adding or removing a transceiver address from the registry +- Setting the token contract address on a bridging contract +- Setting the Wormhole Core Contract address on a bridging contract +- Setting the registered bridging contract address on the token contract - ```bash - ntt init Testnet - ``` +This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +--- END CONTENT --- -=== "Mainnet" +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Access Control +description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +categories: NTT, Transfer +--- - ```bash - ntt init Mainnet - ``` +## Owner and Pauser Roles -Ensure you have set up your environment correctly: +Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). -```bash -export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY -``` +NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. -Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: +- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused +- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts -```bash -# Set scanner API Keys as environment variables -export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY -export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY +You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. -# Add each chain -# The contracts will be automatically verified using the scanner API keys above -ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +```json +{ + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": true, // set to true to pause the contract + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + //... + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } +} ``` -While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. +!!! note + While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. -The `ntt add-chain` command takes the following parameters: +The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. -- Name of each chain -- Version of NTT to deploy (use `--latest` for the latest contract versions) -- Mode (either `burning` or `locking`) -- Your token contract address +Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. +--- END CONTENT --- -The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Rate Limiting +description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. +categories: NTT, Transfer +--- -## Configure NTT +## Introduction -The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: +The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. -- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain -- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: +If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. - For Solana, the limits are set with 9 decimal places: - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - } - ``` +You can configure the following limits on every chain where NTT is deployed directly using the manager: - For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: - ```json - "inbound": { - "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia - } - ``` +- **Sending limit** - a single outbound limit for sending tokens from the chain +- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum - This initial configuration ensures that the rate limits are correctly represented for each chain's token precision - -- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file +Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. -After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. +## Update Rate Limits -## Set Token Minter to NTT Manager +To configure or update the sending and receiving rate limits, follow these steps: -The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. +1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts -!!! note - The required NTT Manager address can be found in the `deployment.json` file. +2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed -- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function ```json - cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + "limits": { + "outbound": "1000.000000000000000000", + "inbound": { + "Ethereum": "100.000000000000000000", + "Arbitrum": "50.000000000000000000" + } + } ``` -- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter + - **`outbound`** - sets the maximum tokens allowed to leave the chain + - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains -By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. +3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain -!!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. + ```bash + ntt push + ``` + +4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status + + ```bash + ntt status + ``` + +???- note "`deployment.json` example" + ```json + { + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": false, + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", + "transceivers": { + "threshold": 1, + "wormhole": { + "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + }, + "limits": { + "outbound": "184467440737.095516150000000000", + "inbound": { + "ArbitrumSepolia": "500.000000000000000000" + } + }, + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } + } + ``` + +## Queuing Mechanism + +When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: + +- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer +- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain + +Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. + +## Cancel Flows + +If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Solana Deployment -description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +title: Native Token Transfers FAQs +description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. categories: NTT, Transfer --- -# Deploy Native Token Transfers on Solana +# Wormhole NTT FAQs -[Native Token Transfers (NTT)](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. +## Do you have an example of how cross-chain lending can be implemented using Wormhole? -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. +Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. -## Prerequisites +## What causes the "No protocols registered for Evm" error in Wormhole SDK? -Before deploying NTT on Solana, ensure you have the following: +This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. -- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} -- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** -- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: -Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. +```rust +import '@wormhole-foundation/sdk-evm-ntt'; +``` -## Overview of the Deployment Process +By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. -Deploying NTT with the CLI on Solana follows a structured process: +## How can I transfer ownership of NTT to a multisig? -1. **Choose your token setup**: +Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. - - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section - - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT +1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) +2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer +3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) - ???- interface "Create and Mint SPL Tokens" - This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. +For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. - 1. **Generate a Solana key pair** - run the following command to create a new wallet: +## How can I specify a custom RPC for NTT? - ```bash - solana-keygen grind --starts-with w:1 --ignore-case - ``` +To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. - 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: +Below’s an example of how the `overrides.json` file should be structured: - ```bash - solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON - ``` +???- code "`overrides.json`" + ```json + { + "chains": { + "Bsc": { + "rpc": "http://127.0.0.1:8545" + }, + "Sepolia": { + "rpc": "http://127.0.0.1:8546" + }, + "Solana": { + "rpc": "http://127.0.0.1:8899" + } + } + } + ``` - 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: +## How can I redeem tokens if NTT rate limits block them on the target chain? - === "Mainnet" - ```bash - solana config set -um - ``` +If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. - === "Testnet" - ```bash - solana config set -ut - ``` +To resolve this: - === "Devnet" - ```bash - solana config set -ud - ``` +1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed +2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain - 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: +In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. - ```bash - solana airdrop 2 - solana balance - ``` +## What are the challenges of deploying NTT to non-EVM chains? - 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} +NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. - ```bash - cargo install spl-token-cli - ``` +## Does the NTT manager function as an escrow account for a hub chain? - 6. **Create a new SPL token** - initialize the token on Solana +Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. - ```bash - spl-token create-token - ``` +## Which functions or events does Connect rely on for NTT integration? - 7. **Create a token account** - generate an account to hold the token +Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: - ```bash - spl-token create-account INSERT_TOKEN_ADDRESS - ``` +- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain +- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion - 8. **Mint tokens** - send 1000 tokens to the created account +These functions ensure Connect can handle token transfers and manage chain-rate limits. - ```bash - spl-token mint INSERT_TOKEN_ADDRESS 1000 - ``` +## How does the relayer contract determine which transceiver to call? - !!! note - NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. +The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. -2. **Choose your [deployment model](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank}**: +## How do I create a verifier or transceiver? - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program +To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. -3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. -Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. +## Can I use Hetzner for the NTT deployment? -By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. -## Set Up NTT +## How can I transfer tokens with NTT with an additional payload? -To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. +You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. -The [NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message +- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message -1. **Create a new NTT project** - set up a deployment workspace +!!!Important + You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. - ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME - ``` +## Why use NTT over xERC20? -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +Shortcomings of xERC20: - === "Mainnet" +- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach +- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies +- **No access control** - there are no built-in access controls for managing token transfers securely +- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security +- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups - ```bash - ntt init Mainnet - ``` +While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. - === "Testnet" +## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? - ```bash - ntt init Testnet - ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. +To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. -### Set Mint Authority +## Is there a way to use NTT tokens with chains that don't currently support NTT? -If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: -If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). +- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) +- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism +- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT -Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. +This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. +--- END CONTENT --- -Follow these steps to set the mint authority using the NTT CLI: +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers EVM Deployment +description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment +# Native Token Transfers (NTT) EVM Development - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +## Deploy Your Token and Ensure Compatibility -2. **Derive the token authority** - generate the PDA, which will manage token minting +If you still need to do so, deploy the token contract to the destination or spoke chains. - ```bash - ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR - ``` +### Requirements for Token Deployment -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. - ```bash - spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA - ``` +#### Burn-and-Mint Mode -## Deploy and Configure NTT +Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: -After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: - -1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: +- `burn(uint256 amount)` +- `mint(address account, uint256 amount)` - === "Burn-and-Mint" +These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. - ```bash - ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` +??? code "View the complete `INttToken` Interface`" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; - === "Hub-and-Spoke" +interface INttToken { + /// @notice Error when the caller is not the minter. + /// @dev Selector 0x5fb5729e. + /// @param caller The caller of the function. + error CallerNotMinter(address caller); - ```bash - ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` + /// @notice Error when the minter is the zero address. + /// @dev Selector 0x04a208c7. + error InvalidMinterZeroAddress(); - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + /// @notice Error when insufficient balance to burn the amount. + /// @dev Selector 0xcf479181. + /// @param balance The balance of the account. + /// @param amount The amount to burn. + error InsufficientBalance(uint256 balance, uint256 amount); -2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: + /// @notice The minter has been changed. + /// @dev Topic0 + /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. + /// @param newMinter The new minter. + event NewMinter(address previousMinter, address newMinter); - ```bash - ntt status - ``` + // NOTE: the `mint` method is not present in the standard ERC20 interface. + function mint(address account, uint256 amount) external; - If needed, sync your local configuration with the on-chain state: + // NOTE: the `setMinter` method is not present in the standard ERC20 interface. + function setMinter(address newMinter) external; - ```bash - ntt pull + // NOTE: NttTokens in `burn` mode require the `burn` method to be present. + // This method is not present in the standard ERC20 interface, but is + // found in the `ERC20Burnable` interface. + function burn(uint256 amount) external; +} ``` -3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. +Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - Open your `deployment.json` file and adjust the values based on your use case: +#### Hub-and-Spoke Mode - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - }, - "outbound": { - "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia - } - ``` +A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. -4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees + - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains + - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers - ```bash - ntt push --payer INSERT_YOUR_KEYPAIR_JSON - ``` +!!! note + The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. +For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. -## Where to Go Next +This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. -
+For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. -- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** +### Key Differences Between Modes - --- + - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently + - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency - After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. +## Deploy NTT - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +Create a new NTT project: -- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** +```bash +ntt new my-ntt-deployment +cd my-ntt-deployment +``` - --- +Initialize a new `deployment.json` file specifying the network: - Follow the NTT Post Deployment Guide for integration examples and testing instructions. +=== "Testnet" - [:custom-arrow: Test Your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} + ```bash + ntt init Testnet + ``` -- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** +=== "Mainnet" - --- + ```bash + ntt init Mainnet + ``` - Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. +Ensure you have set up your environment correctly: - [:custom-arrow: Use Connect to Integrate NTT](/docs/build/transfers/connect/){target=\_blank} +```bash +export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY +``` -
---- END CONTENT --- +Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ ---- BEGIN CONTENT --- ---- -title: Deploy Native Token Transfers with Launchpad -description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -categories: NTT, Transfer ---- +```bash +# Set scanner API Keys as environment variables +export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY +export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY -# Deploy Native Token Transfers with Launchpad +# Add each chain +# The contracts will be automatically verified using the scanner API keys above +ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +``` -## Introduction +While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. -The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. +The `ntt add-chain` command takes the following parameters: -Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. +- Name of each chain +- Version of NTT to deploy (use `--latest` for the latest contract versions) +- Mode (either `burning` or `locking`) +- Your token contract address -The Launchpad automates deployment, reducing complexity and saving time. +The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. -This guide covers: +## Configure NTT - - Launching a new cross-chain token - - Expanding an existing token for NTT - - Managing tokens via the dashboard and settings +The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: -## Prerequisites +- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain +- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: - - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) - - Minimum ETH (or equivalent) for gas fees per deployment + For Solana, the limits are set with 9 decimal places: + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + } + ``` -## Supported Blockchains + For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: + ```json + "inbound": { + "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia + } + ``` -The NTT Launchpad currently supports deployments on the following mainnet chains: + This initial configuration ensures that the rate limits are correctly represented for each chain's token precision + +- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file - - Ethereum - - Arbitrum One - - Base - - Berachain - - Blast - - BNB Smart Chain - - Ink - - Optimism Mainnet - - Polygon +After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. -## Choose Your Path +## Set Token Minter to NTT Manager -Once ready, choose an option to proceed: +The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract +!!! note + The required NTT Manager address can be found in the `deployment.json` file. -## Launch a Cross-Chain Token +- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function + ```json + cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + ``` -Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: +- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** +By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) - -2. Select **Launch a Cross-Chain Token** +!!!important + To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. +--- END CONTENT --- - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Solana Deployment +description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- -3. Set the token details: - 1. Select the **home network** from the dropdown menu - 2. Enter the **name** for the token - 3. Enter the **symbol** of the token - 4. Provide the **initial supply** - 5. To the token details, click **Next** +# Deploy Native Token Transfers on Solana - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -4. Select the deployment chains: - 1. The home network where your token will be deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) +By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction +## Prerequisites - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) +Before deploying NTT on Solana, ensure you have the following: -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} +- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** +- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) +Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +## Overview of the Deployment Process -8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. +Deploying NTT with the CLI on Solana follows a structured process: -## Expand Your Existing Token +1. **Choose your token setup**: -Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: + - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section + - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + ???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + 1. **Generate a Solana key pair** - run the following command to create a new wallet: -2. Select **Expand Your Existing Token** + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: -3. Enter the token details: - 1. Choose the home network where your token is already deployed (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: -4. Select the chains to deploy your token to: - 1. The home network where your token is already deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 1. Click **Next** + === "Mainnet" + ```bash + solana config set -um + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + === "Testnet" + ```bash + solana config set -ut + ``` -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + === "Devnet" + ```bash + solana config set -ud + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + ```bash + solana airdrop 2 + solana balance + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + ```bash + cargo install spl-token-cli + ``` -8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details + 6. **Create a new SPL token** - initialize the token on Solana -## Explore the Launchpad Dashboard + ```bash + spl-token create-token + ``` -To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. + 7. **Create a token account** - generate an account to hold the token -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` -The dashboard provides a high-level view of your token across all deployed chains, including: + 8. **Mint tokens** - send 1000 tokens to the created account - - Token addresses for each chain - - Supply distribution visualization - - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -## Settings +2. **Choose your [deployment model](TODO){target=\_blank}**: -The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program -### Chain Management +3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode -Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. +Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -From this section, you can also: +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain +## Set Up NTT -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) +To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -### Role Management +The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: -This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +1. **Create a new NTT project** - set up a deployment workspace - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers + ```bash + ntt new INSERT_PROJECT_NAME + cd INSERT_PROJECT_NAME + ``` -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) +2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings -### Security Threshold + === "Mainnet" -Determine and update how transceivers interact with the token. [Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. + ```bash + ntt init Mainnet + ``` -A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. + === "Testnet" - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + ```bash + ntt init Testnet + ``` +!!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) +### Set Mint Authority -### Peer Chains Limits +If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. -Define the transfer restrictions for each connected network. You can adjust: +If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains +Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. -Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. +Follow these steps to set the mint authority using the NTT CLI: -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) ---- END CONTENT --- +1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` -# Install the Native Token Transfers CLI +2. **Derive the token authority** - generate the PDA, which will manage token minting -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. + ```bash + ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR + ``` -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +3. **Set SPL token mint authority** - delegate minting control to the derived PDA -
+ ```bash + spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA + ``` -## Install NTT CLI +## Deploy and Configure NTT -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: +After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} +1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: -Follow these steps to install the NTT CLI: + === "Burn-and-Mint" -1. Run the installation command in your terminal: + ```bash + ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` + + === "Hub-and-Spoke" + + ```bash + ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` + + !!! tip + The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + +2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ntt status ``` -2. Verify the NTT CLI is installed: + If needed, sync your local configuration with the on-chain state: ```bash - ntt --version + ntt pull ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI - -## Update NTT CLI +3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. -To update an existing NTT CLI installation, run the following command in your terminal: + Open your `deployment.json` file and adjust the values based on your use case: -```bash -ntt update -``` + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + }, + "outbound": { + "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia + } + ``` -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. +4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees -For local development, you can update your CLI version from a specific branch or install from a local path. + ```bash + ntt push --payer INSERT_YOUR_KEYPAIR_JSON + ``` -To install from a specific branch, run: +### Troubleshoot Deployment Issues + +If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. -```bash -ntt update --branch foo -``` +## Where to Go Next -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` +
-Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. +- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** -## Where to Go Next + --- -
+ After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** +- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** --- - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. + Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** +- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** --- - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. + Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank}
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +title: Deploy Native Token Transfers with Launchpad +description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. categories: NTT, Transfer --- -# Native Token Transfers Post Deployment +# Deploy Native Token Transfers with Launchpad -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): +## Introduction -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment +The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. -## Manual Relaying for Solana Transfers +Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. +The Launchpad automates deployment, reducing complexity and saving time. -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. +This guide covers: -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. + - Launching a new cross-chain token + - Expanding an existing token for NTT + - Managing tokens via the dashboard and settings -## Where to Go Next +## Prerequisites -
+ - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) + - Minimum ETH (or equivalent) for gas fees per deployment -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** +## Supported Blockchains - --- +The NTT Launchpad currently supports deployments on the following mainnet chains: - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + - Ethereum + - Arbitrum One + - Base + - Berachain + - Blast + - BNB Smart Chain + - Ink + - Optimism Mainnet + - Polygon - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) +## Choose Your Path -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** +Once ready, choose an option to proceed: + + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains + - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + +## Launch a Cross-Chain Token + +Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: + +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Launch a Cross-Chain Token** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) + +3. Set the token details: + 1. Select the **home network** from the dropdown menu + 2. Enter the **name** for the token + 3. Enter the **symbol** of the token + 4. Provide the **initial supply** + 5. To the token details, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) + +4. Select the deployment chains: + 1. The home network where your token will be deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) + +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + +8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. + +## Expand Your Existing Token + +Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: + +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Expand Your Existing Token** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) + +3. Enter the token details: + 1. Choose the home network where your token is already deployed (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) + +4. Select the chains to deploy your token to: + 1. The home network where your token is already deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 1. Click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + +8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details + +## Explore the Launchpad Dashboard + +To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) + +The dashboard provides a high-level view of your token across all deployed chains, including: + + - Token addresses for each chain + - Supply distribution visualization + - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) + +## Settings + +The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. + +### Chain Management + +Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. + +From this section, you can also: + + - **Pause the token** – temporarily turn off transfers on the selected chain + - **Deploy to a new chain** – expand your token by deploying it to an additional chain + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) + +### Role Management + +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. + + - **Manager’s Owner** – the owner through the `NTTOwner` proxy + - **Pauser** – the address authorized to pause transfers + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) + +### Security Threshold + +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. + +A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. + + - **Registered Transceivers** – displays the number of registered transceivers and their addresses + - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) + +### Peer Chains Limits + +Define the transfer restrictions for each connected network. You can adjust: + + - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain + - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + +Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +--- BEGIN CONTENT --- +--- +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer +--- + +# NTT CLI Commands + +## Introduction + +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. + +If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. + +## Table of Commands + +The following table lists the available NTT CLI commands, descriptions, and examples. + +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. + +### General Commands + +| Command | Description | Examples | +|-----------------------------------------|-------------------------------------------------------|--------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| +| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | + +### Configuration Commands + +| Command | Description | Examples | +|---------------------------------------------|----------------------------------------|-------------------------------------| +| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| +| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| + +### Solana Commands + +| Command | Description | Examples | +|-----------------------------------------------|---------------------------------------------------------|------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| +| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| +| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| + +## Where to Go Next + +
+ + +- :octicons-gear-16:{ .lg .middle } **Configure NTT** --- - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) + +- :octicons-question-16:{ .lg .middle } **NTT FAQs** + + --- + + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. + + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/)
--- END CONTENT --- @@ -1624,459 +1881,304 @@ If you encounter issues during the NTT deployment process, check the following c ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers FAQs -description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -categories: NTT, Transfer +## Basics Concepts [shared: true] + +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. + --- -# Wormhole NTT FAQs +## List of shared concept pages: -## Do you have an example of how cross-chain lending can be implemented using Wormhole? -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. +## Full content for shared concepts: -Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/learn/transfers/native-token-transfers/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ +--- BEGIN CONTENT --- +--- +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +categories: Basics +--- -## What causes the "No protocols registered for Evm" error in Wormhole SDK? +# Wormhole Use Cases -This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. +
+
-To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: +## Cross-Chain Swaps and Liquidity Aggregation -```rust -import '@wormhole-foundation/sdk-evm-ntt'; -``` +Enable seamless swaps between chains with real-time liquidity routing. -By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. +
+
-## How can I transfer ownership of NTT to a multisig? +🛠 **Wormhole products used:** -Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) -2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer -3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. +
+
-## How can I specify a custom RPC for NTT? -To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. +
+
-Below’s an example of how the `overrides.json` file should be structured: +## Borrowing and Lending Across Chains -???- code "`overrides.json`" - ```json - { - "chains": { - "Bsc": { - "rpc": "http://127.0.0.1:8545" - }, - "Sepolia": { - "rpc": "http://127.0.0.1:8546" - }, - "Solana": { - "rpc": "http://127.0.0.1:8899" - } - } - } - ``` +Let users borrow assets on one chain using collateral from another. -## How can I redeem tokens if NTT rate limits block them on the target chain? +
+
-If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. +🛠 **Wormhole products used:** -To resolve this: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed -2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. +
+
-## What are the challenges of deploying NTT to non-EVM chains? -NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. +
+
-## Does the NTT manager function as an escrow account for a hub chain? +## Real-Time Price Feeds and Trading Strategies -Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. +Fetch price feeds across multiple chains for DeFi applications. -## Which functions or events does Connect rely on for NTT integration? +
+
-Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: +🛠 **Wormhole products used:** -- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain -- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -These functions ensure Connect can handle token transfers and manage chain-rate limits. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## How does the relayer contract determine which transceiver to call? +
+
-The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. -## How do I create a verifier or transceiver? +
+
-To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. +## Asset Movement Between Bitcoin and Other Chains -For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. +Enable direct BTC transfers without wrapped assets. -## Can I use Hetzner for the NTT deployment? +
+
-No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. +🛠 **Wormhole products used:** -## How can I transfer tokens with NTT with an additional payload? +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message -- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message +
+
-!!!Important - You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. +
+
-## Why use NTT over xERC20? +## Decentralized Social Platforms -Shortcomings of xERC20: +Enable seamless communication and asset transfer across decentralized social networks. -- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach -- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies -- **No access control** - there are no built-in access controls for managing token transfers securely -- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security -- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups +
+
-While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. +🛠 **Wormhole products used:** -## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards -To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} -## Is there a way to use NTT tokens with chains that don't currently support NTT? +
+
-Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: -- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) -- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism -- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT +
+
-This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. ---- END CONTENT --- +## Memecoin Launchpads -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/managers-transceivers/ ---- BEGIN CONTENT --- ---- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -categories: NTT, Transfer ---- +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. -# Managers and Transceivers +
+
-## Managers +🛠 **Wormhole products used:** -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` +
+
-- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` +
+
-- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected +## Cross-Chain Perpetuals - ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner - ``` +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -## Transceivers +
+
-_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: +🛠 **Wormhole products used:** -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager - ``` +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees +
+
- ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) - ``` -## Lifecycle of a Message +
+
-### EVM +## Gas Abstraction -#### Transfer +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. +
+
-**Events** +🛠 **Wormhole products used:** -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); -``` +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments -#### Rate Limit +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. +
+
-If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. +
+
-If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. +## Bridging Intent Library -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -**Events** +
+
-```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); -``` +🛠 **Wormhole products used:** -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` - -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` - -#### Send - -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). - -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. - -**Events** - -```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); -``` - -#### Receive - -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. - -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. - -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. - -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. - -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. - -**Events** - -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); -``` +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); -``` +
+
-#### Mint or Unlock -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. +
+
-**Events** +## Multichain Prediction Markets -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. -### Solana +
+
-#### Transfer +🛠 **Wormhole products used:** -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -Depending on the mode and instruction, the following will be produced in the program logs: +
+
-```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. +
+
-#### Rate Limit +## Cross-Chain Payment Widgets -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -If the transfer amount fits within the current capacity: +
+
-- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. +🛠 **Wormhole products used:** -If the transfer amount doesn't fit within the current capacity: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -#### Send +
+
-The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. +
+
-!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. +## Oracle Networks -The following will be produced in the program logs: +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -```ts -Program log: Instruction: ReleaseOutbound -``` +
+
-#### Receive +🛠 **Wormhole products used:** -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -The following will be produced in the program logs: +
+
-```ts -Program log: Instruction: ReceiveMessage -``` -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. +
+
-The following will be produced in the program logs: +## Cross-Chain Staking -```ts -Program log: Instruction: Redeem -``` +Enable users to stake assets on one chain while earning rewards or securing networks on another. -#### Mint or Unlock +
+
-The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. +🛠 **Wormhole products used:** -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks -Depending on the mode and instruction, the following will be produced in the program logs: +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock -``` +
+
--- END CONTENT --- -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- title: Glossary @@ -2153,2077 +2255,1666 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Infrastructure Components - -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +# Get Started with Core Contracts -## Get Started +## Introduction -Start here for an overview of Wormhole architecture components and security mechanisms: +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -
+While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- :octicons-book-16:{ .lg .middle } **Architecture Overview** +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - --- +## Prerequisites - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +To interact with the Wormhole Core Contract, you'll need the following: - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -- :octicons-book-16:{ .lg .middle } **Security** +## How to Interact with Core Contracts - --- +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - [:custom-arrow: Learn About Security](/docs/protocol/security/) +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -
+### Sending Messages -## Explore Components +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +=== "EVM" -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -## Next Steps + ??? interface "Parameters" -
+ `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -- :octicons-book-16:{ .lg .middle } **Messaging Components** + --- - --- + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers + --- - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** + ??? interface "Returns" - --- - - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. - - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- - -# Architecture - -## Overview - -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. - -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. - - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: - - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - -## On-Chain Components - -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract - -## Off-Chain Components - -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Core Contracts** - - --- - - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - -- :octicons-tools-16:{ .lg .middle } **Core Messaging** - - --- - - Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. - -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - -## Key Functions - -Key functions of the Wormhole Core Contract include the following: - -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - -## How the Core Contract Works - -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. - -The following describes the role of the Wormhole Core Contract in message transfers: - -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions - -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - -### Message Submission - -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page - -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. - -### Message Reception - -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - -## Multicast - -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. - -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. - -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. - -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - - --- - - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - - --- - - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ ---- BEGIN CONTENT --- ---- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics ---- - -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing - -The following sections explore each principle in detail. - -### Decentralization - -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. - -Two common approaches to decentralization have notable limitations: - -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment - -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. - -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? - -To answer that, consider these key constraints and design decisions: - -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants - -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. - -### Modularity - -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - -### Chain Agnosticism - -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - -### Scalability - -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - -### Upgradeable - -Wormhole is designed to adapt and evolve in the following ways: - -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Relayers** - - --- - - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - - --- - - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ ---- BEGIN CONTENT --- ---- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -categories: Basics ---- - -# Relayers - -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - -There are three primary types of relayers discussed: - -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - -## Fundamentals - -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - -Key characteristics of VAAs include: - -- Public emission from the Guardian Network - -- Authentication through signatures from the Guardian Network - -- Verifiability by any entity or any Wormhole Core Contract - -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - -Keep in mind the following security considerations around relayers: - -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks - -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain - -## Client-Side Relaying - -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. - -### Key Features - -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs - -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - -### Implementation - -Users themselves carry out the three steps of the cross-chain process: - -1. Perform an action on chain A - -2. Retrieve the resulting VAA from the Guardian Network - -3. Perform an action on chain B using the VAA - -### Considerations - -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - -- Users must sign all required transactions with their own wallet - -- Users must have funds to pay the transaction fees on every chain involved - -- The user experience may be cumbersome due to the manual steps involved - -## Custom Relayers - -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - -### Key Features - -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application - -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - -### Implementation - -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - -### Considerations - -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - -- Development work and hosting of relayers are required - -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -## Wormhole Relayers + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -### Key Features +// Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -### Implementation +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -The Wormhole relayer integration involves two key steps: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +=== "Solana" -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -### Considerations + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. + ??? interface "Parameters" -- All computations are performed on-chain + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- Potentially less gas-efficient compared to custom relayers + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- Support may not be available for all chains + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -## Next Steps + ??? child "Type `PostMessage<'info>`" -
+ ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -- :octicons-book-16:{ .lg .middle } **Spy** + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - --- + --- - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `batch_id` ++"u32"++ + + An identifier for the message batch. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. - --- + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - --- + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -# Spy +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. +### Receiving Messages -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. +The way a message is received and handled depends on the environment. -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. +=== "EVM" -## Key Features + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Integrator Use Case + ??? interface "Parameters" -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ??? interface "Returns" -## Observable Message Categories + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -A Spy can access the following categories of messages shared over the gossip protocol: + ??? child "Struct `VM`" -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status + ??? interface "Example" - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## Additional Resources + // Perform safety checks here -
+ // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + // Your custom application logic here +} + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +=== "Solana" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + Retrieve the raw message data: - --- + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. + ??? interface "Example" - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +#### Validating the Emitter - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -
+Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Next Steps +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -
+This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - --- +await tx.wait(); +``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +#### Additional Checks - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- :octicons-code-16:{ .lg .middle } **Use Queries** +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - --- +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +## Source Code References - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +# Wormhole Relayer -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +## Introduction -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +## Get Started with the Wormhole Relayer -## VAA Format +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -The basic VAA consists of header and body components described as follows: +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- Where each `signature` is: +### Wormhole Relayer Interfaces - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Interact with the Wormhole Relayer -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -## Consistency and Finality +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +Your initial set up should resemble the following: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Signatures +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +contract Example { + IWormholeRelayer public wormholeRelayer; -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} ``` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Be aware of the following considerations when working with attestations: +### Send a Message -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -### Token Transfer with Message +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +### Receive a Message -### Governance +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -#### Action Structure +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +## Delivery Guarantees -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -#### Actions +## Delivery Statuses -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Lifetime of a Message +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Other Considerations -## Next Steps +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -
+- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -- :octicons-book-16:{ .lg .middle } **Guardians** +## Track the Progress of Messages with the Wormhole CLI - --- +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +=== "Mainnet" - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +=== "Testnet" - --- + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +## Step-by-Step Tutorial -
+For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# Introduction to Wormhole - -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +# Products -## What Problems Does Wormhole Solve? +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Critical problems Wormhole addresses include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## Transfer Products -## What Does Wormhole Offer? +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +
-## What Isn't Wormhole? +::spantable:: -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -## Use Cases of Wormhole +::end-spantable:: -Consider the following examples of potential applications enabled by Wormhole: +
-- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -## Explore +## Real-time Data -Discover more about the Wormhole ecosystem, components, and protocols: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +## Multichain Governance -## Demos +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# Architecture - +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -!!! note - Wormhole Integration Complete? +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Supported Blockchains + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Wormhole supports a growing number of blockchains. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - - -
+## On-Chain Components -### EVM +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Off-Chain Components -### SVM +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Core Contracts** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. -### Move VM + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -### Sui Move VM + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Security +# Core Contracts -## Core Security Assumptions +## Introduction -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -In summary: +## Key Functions -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Key functions of the Wormhole Core Contract include the following: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -## Guardian Network +## How the Core Contract Works -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -### Governance +The following describes the role of the Wormhole Core Contract in message transfers: -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +### Message Submission -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -Via governance, the Guardians can: +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Message Reception -## Monitoring +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +## Multicast -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -Guardians monitor: +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -## Asset Layer Protections +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +## Next Steps -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +
-In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -## Open Source + --- -Wormhole builds in the open and is always open source. + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -## Audits +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + --- -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -## Bug Bounties +
+--- END CONTENT --- -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Guardian -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +Guardians fulfill their role in the messaging protocol as follows: -## Learn More +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- +## Guardian Network -# Get Started with Core Contracts +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Introduction +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +The following sections explore each principle in detail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +### Decentralization -## Prerequisites +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -To interact with the Wormhole Core Contract, you'll need the following: +Two common approaches to decentralization have notable limitations: -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -## How to Interact with Core Contracts +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +To answer that, consider these key constraints and design decisions: -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -### Sending Messages +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +### Modularity -=== "EVM" +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +### Chain Agnosticism + +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +### Scalability - ??? interface "Parameters" +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +### Upgradeable - --- +Wormhole is designed to adapt and evolve in the following ways: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - ??? interface "Returns" +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Next Steps - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +
-// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +- :octicons-book-16:{ .lg .middle } **Relayers** -// Check fee and send parameters + --- -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -4657,245 +4348,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -5079,4 +4616,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 93fafb85c..43ff33532 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -13,111 +13,13 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/queries/ ---- BEGIN CONTENT --- ---- -title: Wormhole Queries -description: Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. -categories: Queries ---- - -# Queries - -## Get Started - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. - -
- -- :octicons-book-16:{ .lg .middle } **Overview** - - --- - - Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST API endpoint, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Learn about Queries](/docs/build/queries/overview/) - -- :octicons-code-16:{ .lg .middle } **Use Queries** - - --- - - Explore a simple demo of interacting with Wormhole Queries using an `eth_call` request to query the supply of wETH on Ethereum using a Wormhole query. - - [:custom-arrow: Get hands-on](/docs/build/queries/use-queries/) - -- :octicons-book-16:{ .lg .middle } **Query FAQs** - - --- - - Explore frequently asked questions about Wormhole Queries. - - [:custom-arrow: Check out the FAQs](/docs/products/queries/faqs/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/queries/faqs/ ---- BEGIN CONTENT --- ---- -title: Queries FAQs -description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. -categories: Queries ---- - -# Wormhole Queries FAQs - -## What libraries are available to handle queries? - - - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses - -- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case - -- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests - -- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses - -!!! note - A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. - -## Are there any query examples? - -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - -- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} - -## What is the format of the response signature? - -The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: - -```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` - -See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. - -!!! note - If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. - -## Can anyone run a query proxy server? - -Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. - -It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. - -## What Does Queries Offer over an RPC Service - -Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/queries/overview/ +Doc-Content: https://wormhole.com/docs/..build/queries/overview/ --- BEGIN CONTENT --- --- title: Queries Overview @@ -221,7 +123,7 @@ You can also check out the following examples of applications that make use of W - [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/queries/use-queries/ +Doc-Content: https://wormhole.com/docs/..build/queries/use-queries/ --- BEGIN CONTENT --- --- title: Use Queries @@ -642,6 +544,60 @@ const tx = await contract.updateCounters( ``` --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/queries/faqs/ +--- BEGIN CONTENT --- +--- +title: Queries FAQs +description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. +categories: Queries +--- + +# Wormhole Queries FAQs + +## What libraries are available to handle queries? + + - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses + +- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case + +- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests + +- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses + +!!! note + A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. + +## Are there any query examples? + +Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: + +- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} +- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} +- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} +- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} + +## What is the format of the response signature? + +The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: + +```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` + +See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. + +!!! note + If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. + +## Can anyone run a query proxy server? + +Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. + +It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. + +## What Does Queries Offer over an RPC Service + +Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -656,2154 +612,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +🛠 **Wormhole products used:** -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -## Next Steps +
+
-
-- :octicons-book-16:{ .lg .middle } **Messaging Components** - - --- +
+
- Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## Cross-Chain Perpetuals - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +
+
- --- +🛠 **Wormhole products used:** - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +
-# Architecture -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +## Gas Abstraction -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +
+
-1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +🛠 **Wormhole products used:** - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -## On-Chain Components +
+
-- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +## Bridging Intent Library -## Next Steps +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Multichain Prediction Markets - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +
-This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +🛠 **Wormhole products used:** -## Key Functions +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -Key functions of the Wormhole Core Contract include the following: +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +
+
-## How the Core Contract Works -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +## Cross-Chain Payment Widgets -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +
+
-### Message Submission +🛠 **Wormhole products used:** -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian +# Glossary -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -Guardians fulfill their role in the messaging protocol as follows: +## Chain ID -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -## Guardian Network +## Consistency Level -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -The Guardian Network is designed to help Wormhole deliver on five key principles: +## Delivery Provider -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -The following sections explore each principle in detail. +## Emitter -### Decentralization +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +## Finality -Two common approaches to decentralization have notable limitations: +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Guardian -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Guardian Network -To answer that, consider these key constraints and design decisions: +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Guardian Set -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Modularity +## Heartbeat -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -### Chain Agnosticism +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +## Observation -### Scalability +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +## Relayer -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +A relayer is any process that delivers VAAs to a destination. -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +## Sequence -### Upgradeable +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -Wormhole is designed to adapt and evolve in the following ways: +## Spy -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## VAA -## Next Steps +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. -
- -- :octicons-book-16:{ .lg .middle } **Relayers** - - --- - - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - - --- - - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Prerequisites -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +To interact with the Wormhole Core Contract, you'll need the following: -## Fundamentals +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +## How to Interact with Core Contracts -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -Key characteristics of VAAs include: +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Public emission from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Authentication through signatures from the Guardian Network +### Sending Messages -- Verifiability by any entity or any Wormhole Core Contract +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +=== "EVM" -Keep in mind the following security considerations around relayers: + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ??? interface "Parameters" -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Client-Side Relaying + --- -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -### Key Features + --- -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + ??? interface "Returns" -### Implementation + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -Users themselves carry out the three steps of the cross-chain process: + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -1. Perform an action on chain A +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -2. Retrieve the resulting VAA from the Guardian Network +// Check fee and send parameters -3. Perform an action on chain B using the VAA +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -### Considerations +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- Users must sign all required transactions with their own wallet + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- Users must have funds to pay the transaction fees on every chain involved +=== "Solana" -- The user experience may be cumbersome due to the manual steps involved + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -## Custom Relayers + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + ??? interface "Parameters" -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -### Key Features + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ??? child "Type `PostMessage<'info>`" -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -### Implementation + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `batch_id` ++"u32"++ + + An identifier for the message batch. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + --- -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -## Wormhole Relayers + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -### Key Features + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -### Implementation + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -The Wormhole relayer integration involves two key steps: +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +### Receiving Messages -### Considerations +The way a message is received and handled depends on the environment. -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +=== "EVM" -- All computations are performed on-chain + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Potentially less gas-efficient compared to custom relayers + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted - -- Support may not be available for all chains - -## Next Steps - -
+ ??? interface "Parameters" -- :octicons-book-16:{ .lg .middle } **Spy** + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. - --- + ??? interface "Returns" - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + ??? child "Struct `VM`" -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - --- + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ??? interface "Example" - --- + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + // Perform safety checks here - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -
---- END CONTENT --- + // Your custom application logic here +} + ``` -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -# Spy +=== "Solana" -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + Retrieve the raw message data: -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -## Key Features + ??? interface "Example" -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -## Integrator Use Case + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +#### Validating the Emitter -## Observable Message Categories +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -A Spy can access the following categories of messages shared over the gossip protocol: +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +await tx.wait(); +``` -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +#### Additional Checks - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -## Additional Resources +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? -
+The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +## Source Code References - --- +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +# Wormhole Relayer - --- +## Introduction - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +## Get Started with the Wormhole Relayer - --- +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
-
+### Wormhole Relayer Interfaces -## Next Steps +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -
+- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -- :octicons-code-16:{ .lg .middle } **Run a Spy** +## Interact with the Wormhole Relayer - --- +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -- :octicons-code-16:{ .lg .middle } **Use Queries** +Your initial set up should resemble the following: - --- +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +contract Example { + IWormholeRelayer public wormholeRelayer; -
---- END CONTENT --- + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -# Verified Action Approvals +### Send a Message -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -## VAA Format +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The basic VAA consists of header and body components described as follows: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); - Where each `signature` is: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +### Receive a Message -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +## Delivery Guarantees -## Consistency and Finality +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -## Signatures +## Delivery Statuses -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -## Payload Types +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -### Token Transfer +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +## Other Considerations -Transferring tokens from the sending chain to the destination chain requires the following steps: +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +## Track the Progress of Messages with the Wormhole CLI -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +=== "Mainnet" -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -### Attestation +=== "Testnet" -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -The message format for token attestation is as follows: +## Step-by-Step Tutorial -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -#### Attestation Tips +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -Be aware of the following considerations when working with attestations: +# Products -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +## Transfer Products -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -### Token Transfer with Message +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +
-- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +::spantable:: -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +::end-spantable:: -### Governance +
-Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -#### Action Structure +## Real-time Data -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +## Multichain Governance -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -#### Actions +# Architecture -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +## Overview -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -## Lifetime of a Message +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -## Next Steps +## On-Chain Components + +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract + +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers + +## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +### Message Reception -## Use Cases of Wormhole +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Consider the following examples of potential applications enabled by Wormhole: +## Multicast -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -## Explore +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -Discover more about the Wormhole ecosystem, components, and protocols: +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -## Demos +## Next Steps -Demos offer more realistic implementations than tutorials: +
-- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -!!! note - Wormhole Integration Complete? + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** + --- -## Supported Blockchains + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -Wormhole supports a growing number of blockchains. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - - -
+
+--- END CONTENT --- -### EVM +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Guardian -### SVM +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Guardians fulfill their role in the messaging protocol as follows: -### AVM +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -### CosmWasm +## Guardian Network -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -### Move VM +The Guardian Network is designed to help Wormhole deliver on five key principles: -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -### NEAR VM +The following sections explore each principle in detail. -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Decentralization -### Sui Move VM +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- ---- END CONTENT --- +Two common approaches to decentralization have notable limitations: -Doc-Content: https://wormhole.com/docs/protocol/security/ ---- BEGIN CONTENT --- ---- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics ---- +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -# Security +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -## Core Security Assumptions +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +To answer that, consider these key constraints and design decisions: -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -In summary: +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +### Modularity -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -## Guardian Network +### Chain Agnosticism -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -### Governance +### Scalability -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +### Upgradeable -Via governance, the Guardians can: +Wormhole is designed to adapt and evolve in the following ways: -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. - -## Monitoring - -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. - -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. - -Guardians monitor: - -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators - -## Asset Layer Protections - -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. - -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. - -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. - -## Open Source - -Wormhole builds in the open and is always open source. - -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -## Audits +## Next Steps -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +
-- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +- :octicons-book-16:{ .lg .middle } **Relayers** -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + --- -## Bug Bounties + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + --- -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. -## Learn More + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. categories: Basics --- -# Get Started with Core Contracts - -## Introduction - -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. - -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Core Contract, you'll need the following: - -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on - -## How to Interact with Core Contracts - -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - -### Sending Messages - -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. - -=== "EVM" - - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: - - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` - - ??? interface "Parameters" - - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. - - --- - - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - - --- - - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - - ??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" - - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); - -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); - -// Check fee and send parameters - -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); - -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); - -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: - - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` - - ??? interface "Parameters" - - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -3237,245 +3065,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -3659,4 +3333,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 77b9b4259..d9399a735 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -6,77 +6,15 @@ It is intended for use with large language models (LLMs) to support developers w This file includes documentation related to the category: Reference ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/reference.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- - -# Reference - -## Get Started - -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. - -
- -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** - - --- - - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** - - --- - - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** - - --- - - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. - - This includes the following protocol contracts: - - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP - - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** - - --- - - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) - -
---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- @@ -596,160 +534,6 @@ categories: Reference Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; - -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` - -=== "Solana" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; - -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` - -The result is a standardized address format that is ready for cross-chain operations. - -### Convert Back to Native Addresses - -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: - -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); - -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` - -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. - -## Use Cases for Wormhole Formatted Addresses - -### Cross-chain Token Transfers - -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. - -### Smart Contract Interactions - -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. - -### DApp Development - -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. - -### Relayers and Infrastructure - -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- @@ -931,4 +715,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 8f1377827..f00911bc3 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -13,9 +13,8 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-relayer.md [type: other] ## Full content for each doc page @@ -224,70 +223,6 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/infrastructure/relayers/ ---- BEGIN CONTENT --- ---- -title: Relayers -description: Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. -categories: Relayers ---- - -# Relayers - -## Get Started - -
- -- :octicons-terminal-16:{ .lg .middle } **Run a Custom Relayer** - - --- - - This section guides you through developing your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. - -
- - Benefits of running your own relayer: - - - You can add logic to customize the delivery of messages - - You can perform off-chain computations resulting in optimized gas costs - -
- - Requirements for running your own relayer: - - - You are responsible for developing and hosting your relayer - - You are responsible for paying target chain fees - - You are responsible for the liveness of your relayer - -
- - [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-relayer/) - -
- -## Additional Resources - -
- -- :octicons-question-16:{ .lg .middle } **What is a Relayer?** - - --- - - Learn about what a relayer is, what role it plays in the delivery of cross-chain messages, and the different types of relayers in the Wormhole ecosystem. - - [:custom-arrow: Learn more about relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-gear-16:{ .lg .middle } **Simplify the Development Process** - - --- - - Use the Wormhole Relayer Engine package as a foundational toolkit to develop your own customized off-chain relaying service, enabling tailored message handling. - - [:custom-arrow: Check out the Relayer Engine source code](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} - -
---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ --- BEGIN CONTENT --- --- @@ -630,2154 +565,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components +🛠 **Wormhole products used:** -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +
+
-## Next Steps -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** +## Cross-Chain Perpetuals - --- +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +
+
- [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +🛠 **Wormhole products used:** -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - --- +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +
+
- [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) -
---- END CONTENT --- +
+
-Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +## Gas Abstraction -# Architecture +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +🛠 **Wormhole products used:** -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +
+
- The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +
+
-## On-Chain Components +## Bridging Intent Library -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +🛠 **Wormhole products used:** -## Next Steps +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -
+🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -- :octicons-book-16:{ .lg .middle } **Core Contracts** +
+
- --- - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +
+
- [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +## Multichain Prediction Markets -- :octicons-tools-16:{ .lg .middle } **Core Messaging** +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +🛠 **Wormhole products used:** - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions + +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. - -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - -## Key Functions - -Key functions of the Wormhole Core Contract include the following: - -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - -## How the Core Contract Works -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +## Cross-Chain Payment Widgets -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +
+
-### Message Submission +🛠 **Wormhole products used:** -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +# Glossary -The following sections explore each principle in detail. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -### Decentralization +## Chain ID -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Two common approaches to decentralization have notable limitations: +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Consistency Level -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Delivery Provider -To answer that, consider these key constraints and design decisions: +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Emitter -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -### Modularity +## Finality -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -### Chain Agnosticism +## Guardian -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -### Scalability +## Guardian Network -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## Guardian Set -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Upgradeable +## Heartbeat -Wormhole is designed to adapt and evolve in the following ways: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Observation -## Next Steps +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -
+## Relayer -- :octicons-book-16:{ .lg .middle } **Relayers** +A relayer is any process that delivers VAAs to a destination. - --- +## Sequence - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +## Spy -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers - -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +# Get Started with Core Contracts -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +## Introduction -There are three primary types of relayers discussed: +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +## Prerequisites -## Fundamentals +To interact with the Wormhole Core Contract, you'll need the following: -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +## How to Interact with Core Contracts -Key characteristics of VAAs include: +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -- Public emission from the Guardian Network +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Authentication through signatures from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Verifiability by any entity or any Wormhole Core Contract +### Sending Messages -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -Keep in mind the following security considerations around relayers: +=== "EVM" -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + ??? interface "Parameters" -## Client-Side Relaying + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + --- -### Key Features + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + --- -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -### Implementation + ??? interface "Returns" -Users themselves carry out the three steps of the cross-chain process: - -1. Perform an action on chain A + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -2. Retrieve the resulting VAA from the Guardian Network + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -3. Perform an action on chain B using the VAA +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -### Considerations +// Check fee and send parameters -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -- Users must sign all required transactions with their own wallet +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -- Users must have funds to pay the transaction fees on every chain involved +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- The user experience may be cumbersome due to the manual steps involved + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -## Custom Relayers +=== "Solana" -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -### Key Features + ??? interface "Parameters" -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -### Implementation + ??? child "Type `PostMessage<'info>`" -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -### Considerations + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `batch_id` ++"u32"++ + + An identifier for the message batch. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + --- -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -## Wormhole Relayers + --- -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -### Key Features + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- **Lower operational costs** - no need to develop, host, or maintain individual relayers + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -### Implementation +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -The Wormhole relayer integration involves two key steps: +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -### Considerations +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +### Receiving Messages -- All computations are performed on-chain +The way a message is received and handled depends on the environment. -- Potentially less gas-efficient compared to custom relayers +=== "EVM" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Support may not be available for all chains + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Next Steps + ??? interface "Parameters" -
+ `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -- :octicons-book-16:{ .lg .middle } **Spy** + ??? interface "Returns" - --- + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + ??? child "Struct `VM`" - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. - --- + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ??? interface "Example" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); - --- + // Perform safety checks here - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) + // Your custom application logic here +} + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +=== "Solana" -# Spy + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + Retrieve the raw message data: -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + ??? interface "Example" -## Key Features - -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -## Integrator Use Case + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +#### Validating the Emitter -## Observable Message Categories +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -A Spy can access the following categories of messages shared over the gossip protocol: +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +await tx.wait(); +``` -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +#### Additional Checks - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -## Additional Resources +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? -
+The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +## Source Code References - --- +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +# Wormhole Relayer - --- +## Introduction - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +## Get Started with the Wormhole Relayer - --- +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
-
+### Wormhole Relayer Interfaces -## Next Steps +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -
+- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -- :octicons-code-16:{ .lg .middle } **Run a Spy** +## Interact with the Wormhole Relayer - --- +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -- :octicons-code-16:{ .lg .middle } **Use Queries** +Your initial set up should resemble the following: - --- +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +contract Example { + IWormholeRelayer public wormholeRelayer; -
---- END CONTENT --- + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -# Verified Action Approvals +### Send a Message -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -## VAA Format +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The basic VAA consists of header and body components described as follows: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); - Where each `signature` is: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +### Receive a Message -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +## Delivery Guarantees -## Consistency and Finality +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -## Signatures +## Delivery Statuses -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -## Payload Types +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -### Token Transfer +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +## Other Considerations -Transferring tokens from the sending chain to the destination chain requires the following steps: +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +## Track the Progress of Messages with the Wormhole CLI -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +=== "Mainnet" -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -### Attestation +=== "Testnet" -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -The message format for token attestation is as follows: +## Step-by-Step Tutorial -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -#### Attestation Tips +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -Be aware of the following considerations when working with attestations: +# Products -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +## Transfer Products -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -### Token Transfer with Message +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +
-- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +::spantable:: -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +::end-spantable:: -### Governance +
-Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -#### Action Structure +## Real-time Data -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +## Multichain Governance -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -#### Actions +# Architecture -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +## Overview -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -## Lifetime of a Message +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract + +## On-Chain Components + +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract + +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers ## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +### Message Reception -## Use Cases of Wormhole +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Consider the following examples of potential applications enabled by Wormhole: +## Multicast -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -## Explore +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -Discover more about the Wormhole ecosystem, components, and protocols: +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole - -## Demos - -Demos offer more realistic implementations than tutorials: - -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs - - - -!!! note - Wormhole Integration Complete? - - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! - - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** - -## Supported Blockchains - -Wormhole supports a growing number of blockchains. - - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -### Move VM + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -### Sui Move VM + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. categories: Basics --- -# Security +## Guardian -## Core Security Assumptions +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +Guardians fulfill their role in the messaging protocol as follows: -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -In summary: +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +## Guardian Network -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Guardian Network +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -### Governance +The following sections explore each principle in detail. -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +### Decentralization -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +Two common approaches to decentralization have notable limitations: -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -Via governance, the Guardians can: +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +To answer that, consider these key constraints and design decisions: -## Monitoring +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +### Modularity -Guardians monitor: +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +### Chain Agnosticism -## Asset Layer Protections +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +### Scalability -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -## Open Source +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -Wormhole builds in the open and is always open source. +### Upgradeable -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +Wormhole is designed to adapt and evolve in the following ways: -## Audits +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +## Next Steps -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. +
-## Bug Bounties +- :octicons-book-16:{ .lg .middle } **Relayers** -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + --- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -## Learn More + --- -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. + + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. categories: Basics --- -# Get Started with Core Contracts - -## Introduction - -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. - -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Core Contract, you'll need the following: - -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on - -## How to Interact with Core Contracts - -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - -### Sending Messages - -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. - -=== "EVM" - - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: - - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` - - ??? interface "Parameters" - - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. - - --- - - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - - --- - - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - - ??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" - - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); - -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); - -// Check fee and send parameters - -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); - -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); - -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: - - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` - - ??? interface "Parameters" - - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -3211,245 +3018,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -3633,4 +3286,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index dc9c57886..ebf253413 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -13,49 +13,60 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/ +Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ --- BEGIN CONTENT --- --- -title: Wormhole Settlement -description: Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. +title: Wormhole Settlement Overview +description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. categories: Settlement, Transfer --- -# Wormhole Settlement +# Wormhole Settlement Overview -## Get Started +## Introduction -This section covers Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. +Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. -
+With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. -- :octicons-question-16:{ .lg .middle } **Overview** +The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - --- +Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. + +## Key Features + +- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well +- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency +- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake + +## Integrator Paths - Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +### SDK Integrators - [:custom-arrow: Learn more about Wormhole Settlement](/docs/learn/transfers/settlement/overview/) +Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. -- :octicons-question-16:{ .lg .middle } **Protocol Architectures** +### NTT Integrators - --- +NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. +### Chain Integrators - [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) +Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. -
+!!!tip + Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. + +## Related Resources + +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ @@ -165,89 +176,6 @@ The protocol provides mechanisms for unlocking the fee once the bridging process - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- - -# Wormhole Settlement Overview - -## Introduction - -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement -description: Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. -categories: Settlement, Transfer ---- - -# Wormhole Settlement - -## Get Started - -This section provides resources to build with Wormhole Settlement, including integrating the Liquidity Layer into your application and running a Solver for efficient cross-chain asset transfers. - -
- -- :octicons-code-16:{ .lg .middle } **Build on the Liquidity Layer** - - --- - - Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. - - [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) - -- :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** - - --- - - Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - - [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) - -
---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- @@ -632,2154 +560,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: - -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +🛠 **Wormhole products used:** -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -## Next Steps +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** - --- +
+
- Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## Cross-Chain Perpetuals - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +
+
- --- +🛠 **Wormhole products used:** - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- -# Architecture +
+
-## Overview +## Gas Abstraction -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +
+
-The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +🛠 **Wormhole products used:** - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -## On-Chain Components +
+
-- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +## Bridging Intent Library -## Next Steps +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Multichain Prediction Markets - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +
-This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +🛠 **Wormhole products used:** -## Key Functions +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -Key functions of the Wormhole Core Contract include the following: +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +
+
-## How the Core Contract Works -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +## Cross-Chain Payment Widgets -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +
+
-### Message Submission +🛠 **Wormhole products used:** -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +# Glossary -The following sections explore each principle in detail. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -### Decentralization +## Chain ID -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Two common approaches to decentralization have notable limitations: +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Consistency Level -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Delivery Provider -To answer that, consider these key constraints and design decisions: +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Emitter -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -### Modularity +## Finality -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -### Chain Agnosticism +## Guardian -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -### Scalability +## Guardian Network -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## Guardian Set -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Upgradeable +## Heartbeat -Wormhole is designed to adapt and evolve in the following ways: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Observation -## Next Steps +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -
+## Relayer -- :octicons-book-16:{ .lg .middle } **Relayers** +A relayer is any process that delivers VAAs to a destination. - --- +## Sequence - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +## Spy -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +## Prerequisites -## Fundamentals +To interact with the Wormhole Core Contract, you'll need the following: -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +## How to Interact with Core Contracts -Key characteristics of VAAs include: +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -- Public emission from the Guardian Network +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Authentication through signatures from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Verifiability by any entity or any Wormhole Core Contract +### Sending Messages -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -Keep in mind the following security considerations around relayers: +=== "EVM" -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + ??? interface "Parameters" -## Client-Side Relaying + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + --- -### Key Features + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + --- -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -### Implementation + ??? interface "Returns" -Users themselves carry out the three steps of the cross-chain process: + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -1. Perform an action on chain A + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -2. Retrieve the resulting VAA from the Guardian Network +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -3. Perform an action on chain B using the VAA +// Check fee and send parameters -### Considerations +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -- Users must sign all required transactions with their own wallet +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- Users must have funds to pay the transaction fees on every chain involved + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- The user experience may be cumbersome due to the manual steps involved +=== "Solana" -## Custom Relayers + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + ??? interface "Parameters" -### Key Features + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ??? child "Type `PostMessage<'info>`" -### Implementation + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -### Considerations + --- -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + `batch_id` ++"u32"++ + + An identifier for the message batch. -- Development work and hosting of relayers are required + --- -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + --- -## Wormhole Relayers + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -### Key Features + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -- **Lower operational costs** - no need to develop, host, or maintain individual relayers + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -### Implementation +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -The Wormhole relayer integration involves two key steps: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -### Considerations +### Receiving Messages -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +The way a message is received and handled depends on the environment. -- All computations are performed on-chain +=== "EVM" -- Potentially less gas-efficient compared to custom relayers + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -- Support may not be available for all chains + ??? interface "Parameters" -## Next Steps + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -
+ ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Spy** + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. - --- + ??? child "Struct `VM`" - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - --- + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + ??? interface "Example" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + // Perform safety checks here - --- + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + // Your custom application logic here +} + ``` - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -
---- END CONTENT --- +=== "Solana" -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -# Spy + Retrieve the raw message data: -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ??? interface "Example" -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -## Key Features + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -## Integrator Use Case +#### Validating the Emitter -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Observable Message Categories +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -A Spy can access the following categories of messages shared over the gossip protocol: +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +await tx.wait(); +``` -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +#### Additional Checks - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -## Additional Resources +## Source Code References -
+For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +# Wormhole Relayer - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +## Introduction -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. - --- +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +## Get Started with the Wormhole Relayer - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. - --- +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +### Wormhole Relayer Interfaces - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -
+- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -## Next Steps +## Interact with the Wormhole Relayer -
+To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. - --- +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +Your initial set up should resemble the following: - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -- :octicons-code-16:{ .lg .middle } **Use Queries** +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; - --- +contract Example { + IWormholeRelayer public wormholeRelayer; - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -
---- END CONTENT --- +### Send a Message -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -# Verified Action Approvals +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -## VAA Format +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -The basic VAA consists of header and body components described as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +### Receive a Message - Where each `signature` is: +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Delivery Guarantees -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -## Consistency and Finality +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +## Delivery Statuses -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -## Signatures +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -## Payload Types +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +## Other Considerations -### Token Transfer +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -Transferring tokens from the sending chain to the destination chain requires the following steps: +## Track the Progress of Messages with the Wormhole CLI -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +=== "Mainnet" -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +=== "Testnet" -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -### Attestation +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. +## Step-by-Step Tutorial -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -The message format for token attestation is as follows: +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +# Products -#### Attestation Tips +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Be aware of the following considerations when working with attestations: +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +## Transfer Products -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +
-### Token Transfer with Message +::spantable:: -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +::end-spantable:: -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +
-- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -### Governance +## Real-time Data -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -#### Action Structure +## Multichain Governance -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +# Architecture -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +## Overview -#### Actions +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -## Lifetime of a Message +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +## On-Chain Components -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract + +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers ## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +### Message Reception -## Use Cases of Wormhole +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Consider the following examples of potential applications enabled by Wormhole: +## Multicast -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -## Explore +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -Discover more about the Wormhole ecosystem, components, and protocols: +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -## Demos +## Next Steps -Demos offer more realistic implementations than tutorials: +
-- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -!!! note - Wormhole Integration Complete? + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** + --- -## Supported Blockchains + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -Wormhole supports a growing number of blockchains. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - - -
+
+--- END CONTENT --- -### EVM +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Guardian -### SVM +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Guardians fulfill their role in the messaging protocol as follows: -### AVM +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -### CosmWasm +## Guardian Network -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -### Move VM +The Guardian Network is designed to help Wormhole deliver on five key principles: -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -### NEAR VM +The following sections explore each principle in detail. -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Decentralization -### Sui Move VM +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- ---- END CONTENT --- +Two common approaches to decentralization have notable limitations: -Doc-Content: https://wormhole.com/docs/protocol/security/ ---- BEGIN CONTENT --- ---- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics ---- +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -# Security +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -## Core Security Assumptions +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +To answer that, consider these key constraints and design decisions: -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -In summary: +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +### Modularity -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -## Guardian Network +### Chain Agnosticism -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -### Governance +### Scalability -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +### Upgradeable -Via governance, the Guardians can: +Wormhole is designed to adapt and evolve in the following ways: -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -## Monitoring +## Next Steps -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +
-Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +- :octicons-book-16:{ .lg .middle } **Relayers** -Guardians monitor: + --- -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -## Asset Layer Protections + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. + --- -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. -## Open Source + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) -Wormhole builds in the open and is always open source. +
+--- END CONTENT --- -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- -## Audits +# Relayers -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} - -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - -## Bug Bounties - -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. - -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - -## Learn More - -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- - -# Get Started with Core Contracts - -## Introduction - -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. - -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Core Contract, you'll need the following: - -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on - -## How to Interact with Core Contracts - -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - -### Sending Messages - -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. - -=== "EVM" - - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: - - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` - - ??? interface "Parameters" - - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. - - --- - - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - - --- - - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - - ??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" - - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); - -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); - -// Check fee and send parameters - -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); - -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); - -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: - - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` - - ??? interface "Parameters" - - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). - - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" - - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -3213,245 +3013,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -3635,4 +3281,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 8dc5ea185..0d1e3d3dc 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -13,114 +13,14 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/toolkit/ ---- BEGIN CONTENT --- ---- -title: Wormhole Tooling -description: This page lists key dev tools, including the WormholeScan Explorer, Wormhole CLI, Wormhole SDKs, and APIs for querying network data. -categories: Solidity-SDK ---- - -# Wormhole Tooling - -Regardless of which network development environment you are using, there are a few Wormhole-specific tools you should know about. - -## Get Started - -
- -- :octicons-telescope-16:{ .lg .middle } **Wormholescan** - - --- - - Wormholescan is an explorer for looking at individual transfer statuses on Mainnet and Testnet. - - [:custom-arrow: Review transactions on Wormholescan](https://wormholescan.io){target=\_blank} - -- :octicons-plug-16:{ .lg .middle } **Wormholescan API** - - --- - - Leverage the Wormholescan API to programmatically access Wormhole network data, including transaction details and VAAs. - - [:custom-arrow: Explore the Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} - -- :octicons-code-square-16:{ .lg .middle } **Wormhole CLI Tool** - - --- - - The Wormhole CLI is a Swiss-Army knife utility command line tool. It is excellent for creating one-off VAAs, parsing VAAs, reading Wormhole contract configurations, and more. - - [:custom-arrow: Get started with the CLI](/docs/build/toolkit/cli/) - -- :octicons-code-square-16:{ .lg .middle } **Wormhole SDK** - - --- - - Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC transfers. - - [:custom-arrow: Get started with the SDK](/docs/tools/typescript-sdk/get-started/) - -- :octicons-code-square-16:{ .lg .middle } **Solidity SDK** - - --- - - Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains. - - [:custom-arrow: Get started with the SDK](/docs/tools/solidity-sdk/sdk-reference/) - -- :octicons-beaker-16:{ .lg .middle } **Tilt** - - --- - - Learn about Tilt, a Wormhole developer environment with a local Kubernetes set up for cross-chain testing with Guardian nodes and relayers for seamless development. - - [:custom-arrow: Get started with Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} - - - -
- -## Additional Resources - -
- -- :octicons-code-square-16:{ .lg .middle } **Wormhole Spy SDK** - - --- - - The Wormhole Spy SDK allows you to listen to all the Guardian Network activity. - - [:custom-arrow: Check out the Spy SDK repository](https://github.com/wormhole-foundation/wormhole/tree/main/spydk/js){target=\_blank} - -- :octicons-pencil-16:{ .lg .middle } **VAA Parser** - - --- - - The VAA Parser is a resource for parsing out details of an encoded VAA. - - [:custom-arrow: Try the VAA Parser](https://wormholescan.io/#/developers/vaa-parser){target=\_blank} - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/toolkit/cli/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ --- BEGIN CONTENT --- --- title: Wormhole CLI @@ -885,7 +785,7 @@ worm info rpc mainnet bsc ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/dev-env/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ --- BEGIN CONTENT --- --- title: Local Dev Environment @@ -950,7 +850,7 @@ https://api.wormholescan.io ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/faqs/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ --- BEGIN CONTENT --- --- title: Toolkit FAQs @@ -1335,2154 +1235,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components - -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: - -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +🛠 **Wormhole products used:** -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -## Next Steps +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** - --- +
+
- Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## Cross-Chain Perpetuals - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +
+
- --- +🛠 **Wormhole products used:** - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- -# Architecture +
+
-## Overview +## Gas Abstraction -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +
+
-The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +🛠 **Wormhole products used:** -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +
+
-## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +
+
-## Off-Chain Components +## Bridging Intent Library -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -## Next Steps +
+
-
+🛠 **Wormhole products used:** -- :octicons-book-16:{ .lg .middle } **Core Contracts** +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - --- - - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Multichain Prediction Markets - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +
-This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +🛠 **Wormhole products used:** -## Key Functions +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -Key functions of the Wormhole Core Contract include the following: +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +
+
-## How the Core Contract Works -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +## Cross-Chain Payment Widgets -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +
+
-### Message Submission +🛠 **Wormhole products used:** -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +# Glossary -The following sections explore each principle in detail. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -### Decentralization +## Chain ID -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Two common approaches to decentralization have notable limitations: +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Consistency Level -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Delivery Provider -To answer that, consider these key constraints and design decisions: +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Emitter -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -### Modularity +## Finality -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -### Chain Agnosticism +## Guardian -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -### Scalability +## Guardian Network -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## Guardian Set -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Upgradeable +## Heartbeat -Wormhole is designed to adapt and evolve in the following ways: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Observation -## Next Steps +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -
+## Relayer -- :octicons-book-16:{ .lg .middle } **Relayers** +A relayer is any process that delivers VAAs to a destination. - --- +## Sequence - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +## Spy -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Prerequisites -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +To interact with the Wormhole Core Contract, you'll need the following: -## Fundamentals +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +## How to Interact with Core Contracts -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -Key characteristics of VAAs include: +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Public emission from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Authentication through signatures from the Guardian Network +### Sending Messages -- Verifiability by any entity or any Wormhole Core Contract +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +=== "EVM" -Keep in mind the following security considerations around relayers: + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ??? interface "Parameters" -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Client-Side Relaying + --- -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -### Key Features + --- -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + ??? interface "Returns" -### Implementation + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -Users themselves carry out the three steps of the cross-chain process: + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -1. Perform an action on chain A +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -2. Retrieve the resulting VAA from the Guardian Network +// Check fee and send parameters -3. Perform an action on chain B using the VAA +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -### Considerations +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- Users must sign all required transactions with their own wallet + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- Users must have funds to pay the transaction fees on every chain involved +=== "Solana" -- The user experience may be cumbersome due to the manual steps involved + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -## Custom Relayers + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + ??? interface "Parameters" -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -### Key Features + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ??? child "Type `PostMessage<'info>`" -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -### Implementation + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `batch_id` ++"u32"++ + + An identifier for the message batch. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + --- -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -## Wormhole Relayers + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -### Key Features + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -### Implementation + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -The Wormhole relayer integration involves two key steps: +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +### Receiving Messages -### Considerations +The way a message is received and handled depends on the environment. -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +=== "EVM" -- All computations are performed on-chain + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Potentially less gas-efficient compared to custom relayers + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ??? interface "Parameters" -- Support may not be available for all chains + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -## Next Steps + ??? interface "Returns" -
+ `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -- :octicons-book-16:{ .lg .middle } **Spy** + ??? child "Struct `VM`" - --- + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - --- + ??? interface "Example" - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + // Perform safety checks here -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - --- + // Your custom application logic here +} + ``` - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +=== "Solana" -
---- END CONTENT --- + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- - -# Spy + Retrieve the raw message data: -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ??? interface "Example" -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -## Key Features + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -## Integrator Use Case +#### Validating the Emitter -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Observable Message Categories +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -A Spy can access the following categories of messages shared over the gossip protocol: +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +await tx.wait(); +``` -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +#### Additional Checks - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -## Additional Resources +## Source Code References -
+For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +# Wormhole Relayer - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +## Introduction -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. - --- +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +## Get Started with the Wormhole Relayer - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. - --- +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +### Wormhole Relayer Interfaces - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -
+- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -## Next Steps +## Interact with the Wormhole Relayer -
+To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. - --- +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +Your initial set up should resemble the following: - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -- :octicons-code-16:{ .lg .middle } **Use Queries** +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; - --- +contract Example { + IWormholeRelayer public wormholeRelayer; - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -
---- END CONTENT --- +### Send a Message -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -# Verified Action Approvals +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -## VAA Format +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -The basic VAA consists of header and body components described as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +### Receive a Message - Where each `signature` is: +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Delivery Guarantees -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -## Consistency and Finality +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +## Delivery Statuses -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -## Signatures +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -## Payload Types +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +## Other Considerations -### Token Transfer +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -Transferring tokens from the sending chain to the destination chain requires the following steps: +## Track the Progress of Messages with the Wormhole CLI -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +=== "Mainnet" -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +=== "Testnet" -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -### Attestation +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. +## Step-by-Step Tutorial -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -The message format for token attestation is as follows: +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +# Products -#### Attestation Tips +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Be aware of the following considerations when working with attestations: +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +## Transfer Products -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +
-### Token Transfer with Message +::spantable:: -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +::end-spantable:: -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +
-- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -### Governance +## Real-time Data -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -#### Action Structure +## Multichain Governance -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +# Architecture -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +## Overview -#### Actions +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -## Lifetime of a Message +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +## On-Chain Components -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract + +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers ## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge - -## Use Cases of Wormhole - -Consider the following examples of potential applications enabled by Wormhole: - -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum - -## Explore - -Discover more about the Wormhole ecosystem, components, and protocols: - -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole - -## Demos - -Demos offer more realistic implementations than tutorials: - -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs - - - -!!! note - Wormhole Integration Complete? - - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! - - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +### Message Reception -## Supported Blockchains +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Wormhole supports a growing number of blockchains. +## Multicast - - -
+Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -### EVM +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -### SVM +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -### Move VM + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -### Sui Move VM + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. categories: Basics --- -# Security +## Guardian -## Core Security Assumptions +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +Guardians fulfill their role in the messaging protocol as follows: -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -In summary: +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +## Guardian Network -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Guardian Network +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -### Governance +The following sections explore each principle in detail. -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +### Decentralization -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +Two common approaches to decentralization have notable limitations: -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -Via governance, the Guardians can: +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +To answer that, consider these key constraints and design decisions: -## Monitoring +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +### Modularity -Guardians monitor: +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +### Chain Agnosticism -## Asset Layer Protections +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +### Scalability -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -## Open Source +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -Wormhole builds in the open and is always open source. +### Upgradeable -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +Wormhole is designed to adapt and evolve in the following ways: -## Audits +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +## Next Steps -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. +
-## Bug Bounties +- :octicons-book-16:{ .lg .middle } **Relayers** -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + --- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -## Learn More + --- -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. + + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. categories: Basics --- -# Get Started with Core Contracts +# Relayers -## Introduction +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +There are three primary types of relayers discussed: -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved -## Prerequisites +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) -To interact with the Wormhole Core Contract, you'll need the following: +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +## Fundamentals -## How to Interact with Core Contracts +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - -### Sending Messages - -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. - -=== "EVM" - - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: - - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` - - ??? interface "Parameters" - - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. - - --- - - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - - --- - - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - - ??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" - - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); - -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); - -// Check fee and send parameters - -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); - -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); - -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: - - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` - - ??? interface "Parameters" - - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). - - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" - - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` - - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. - - ??? child "Type `PostMessage<'info>`" - - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` - - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - - --- - - `batch_id` ++"u32"++ - - An identifier for the message batch. - - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -3916,245 +3688,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -4338,4 +3956,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index af2e7193e..1dcf7ba57 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -13,82 +13,13 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - -### How Does It Work? - -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. - -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). - -### Token Transfer Flow - -The transfer process is simple yet secure, involving a few key steps: - -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody - -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) - -### Key Features of the Token Bridge - -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - -### Message and Payload Structure - -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract - -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - -### Security and Authorization - -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - -### Portal Bridge - -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/transfers/token-bridge/ +Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ --- BEGIN CONTENT --- --- title: Get Started with Token Bridge @@ -308,6 +239,85 @@ For a deeper understanding of the Token Bridge implementation and to review the ## Portal Bridge A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ +--- BEGIN CONTENT --- +--- +title: Token Bridge +description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. +categories: Token-Bridge, Transfer +--- + +# Token Bridge + +Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. + +Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. + +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. + +This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. + +### How Does It Work? + +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. + +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. + +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. + +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). + +### Token Transfer Flow + +The transfer process is simple yet secure, involving a few key steps: + +1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message +4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody + +![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) + +### Key Features of the Token Bridge + +The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. + +The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. + +### Message and Payload Structure + +To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. + +- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens +- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain +- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name +- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain +- `UpgradeContract` - upgrade the contract + +Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. + +One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. + +### Security and Authorization + +The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. + +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. + +### Portal Bridge + +A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ +--- BEGIN CONTENT --- +--- +title: Token Bridge FAQs +description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +categories: Token-Bridge, Transfer +--- ## FAQs @@ -355,2154 +365,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components +🛠 **Wormhole products used:** -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] - -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. - -## Next Steps +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** - --- +
+
- Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## Cross-Chain Perpetuals - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +
+
- --- +🛠 **Wormhole products used:** - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +
-# Architecture -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +## Gas Abstraction -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +
+
-1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +🛠 **Wormhole products used:** - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -## On-Chain Components +
+
-- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +## Bridging Intent Library -## Next Steps +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Multichain Prediction Markets - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks.
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +
-This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +🛠 **Wormhole products used:** -## Key Functions +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -Key functions of the Wormhole Core Contract include the following: +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +
+
-## How the Core Contract Works -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +
+
-The following describes the role of the Wormhole Core Contract in message transfers: +## Cross-Chain Payment Widgets -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +
+
-### Message Submission +🛠 **Wormhole products used:** -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian +# Glossary -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -Guardians fulfill their role in the messaging protocol as follows: +## Chain ID -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -## Guardian Network +## Consistency Level -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -The Guardian Network is designed to help Wormhole deliver on five key principles: +## Delivery Provider -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -The following sections explore each principle in detail. +## Emitter -### Decentralization +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +## Finality -Two common approaches to decentralization have notable limitations: +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Guardian -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Guardian Network -To answer that, consider these key constraints and design decisions: +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Guardian Set -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Modularity +## Heartbeat -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -### Chain Agnosticism +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +## Observation -### Scalability +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +## Relayer -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +A relayer is any process that delivers VAAs to a destination. -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +## Sequence -### Upgradeable +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -Wormhole is designed to adapt and evolve in the following ways: +## Spy -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - -## Next Steps - -
- -- :octicons-book-16:{ .lg .middle } **Relayers** - - --- - - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Prerequisites -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +To interact with the Wormhole Core Contract, you'll need the following: -## Fundamentals +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +## How to Interact with Core Contracts -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -Key characteristics of VAAs include: +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Public emission from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Authentication through signatures from the Guardian Network +### Sending Messages -- Verifiability by any entity or any Wormhole Core Contract +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +=== "EVM" -Keep in mind the following security considerations around relayers: + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ??? interface "Parameters" -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Client-Side Relaying + --- -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -### Key Features + --- -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + ??? interface "Returns" -### Implementation + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -Users themselves carry out the three steps of the cross-chain process: + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -1. Perform an action on chain A +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -2. Retrieve the resulting VAA from the Guardian Network +// Check fee and send parameters -3. Perform an action on chain B using the VAA +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -### Considerations +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- Users must sign all required transactions with their own wallet + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- Users must have funds to pay the transaction fees on every chain involved +=== "Solana" -- The user experience may be cumbersome due to the manual steps involved + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -## Custom Relayers + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. + ??? interface "Parameters" -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -### Key Features + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ??? child "Type `PostMessage<'info>`" -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -### Implementation + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `batch_id` ++"u32"++ + + An identifier for the message batch. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + --- -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -## Wormhole Relayers + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -### Key Features + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -### Implementation + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -The Wormhole relayer integration involves two key steps: +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +### Receiving Messages -### Considerations +The way a message is received and handled depends on the environment. -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +=== "EVM" -- All computations are performed on-chain + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- Potentially less gas-efficient compared to custom relayers - -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -- Support may not be available for all chains + ??? interface "Parameters" -## Next Steps + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -
+ ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Spy** + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. - --- + ??? child "Struct `VM`" - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - --- + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + ??? interface "Example" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + // Perform safety checks here - --- + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + // Your custom application logic here +} + ``` - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -
---- END CONTENT --- +=== "Solana" -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -# Spy + Retrieve the raw message data: -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ??? interface "Example" -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -## Key Features + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -## Integrator Use Case +#### Validating the Emitter -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Observable Message Categories +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -A Spy can access the following categories of messages shared over the gossip protocol: +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +await tx.wait(); +``` -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +#### Additional Checks - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -## Additional Resources +## Source Code References -
+For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -- :octicons-code-16:{ .lg .middle } **Spy Source Code** +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +# Wormhole Relayer - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} +## Introduction -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. - --- +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +## Get Started with the Wormhole Relayer - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. - --- +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +### Wormhole Relayer Interfaces - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -
+- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -## Next Steps +## Interact with the Wormhole Relayer -
+To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. - --- +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +Your initial set up should resemble the following: - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -- :octicons-code-16:{ .lg .middle } **Use Queries** +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; - --- +contract Example { + IWormholeRelayer public wormholeRelayer; - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -
---- END CONTENT --- +### Send a Message -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -# Verified Action Approvals +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -## VAA Format +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -The basic VAA consists of header and body components described as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +### Receive a Message - Where each `signature` is: +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Delivery Guarantees -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -## Consistency and Finality +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +## Delivery Statuses -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -## Signatures +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -## Payload Types +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). +## Other Considerations -### Token Transfer +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -Transferring tokens from the sending chain to the destination chain requires the following steps: +## Track the Progress of Messages with the Wormhole CLI -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +=== "Mainnet" -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +=== "Testnet" -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -### Attestation +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. +## Step-by-Step Tutorial -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -The message format for token attestation is as follows: +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +# Products -#### Attestation Tips +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Be aware of the following considerations when working with attestations: +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +## Transfer Products -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +
-### Token Transfer with Message +::spantable:: -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +::end-spantable:: -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +
-- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -### Governance +## Real-time Data -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -#### Action Structure +## Multichain Governance -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +# Architecture -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +## Overview -#### Actions +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -## Lifetime of a Message +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +## On-Chain Components -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract + +## Off-Chain Components + +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers ## Next Steps
-- :octicons-book-16:{ .lg .middle } **Guardians** +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Introduction to Wormhole +# Core Contracts -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +## Introduction -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +## Key Functions -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +## How the Core Contract Works -## What Problems Does Wormhole Solve? +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +The following describes the role of the Wormhole Core Contract in message transfers: -Critical problems Wormhole addresses include: +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -## What Does Wormhole Offer? +### Message Submission -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -## What Isn't Wormhole? +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +### Message Reception -## Use Cases of Wormhole +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -Consider the following examples of potential applications enabled by Wormhole: +## Multicast -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -## Explore +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -Discover more about the Wormhole ecosystem, components, and protocols: +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -## Demos +## Next Steps -Demos offer more realistic implementations than tutorials: +
-- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -!!! note - Wormhole Integration Complete? + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** + --- -## Supported Blockchains + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -Wormhole supports a growing number of blockchains. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - - -
+
+--- END CONTENT --- -### EVM +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Guardian -### SVM +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Guardians fulfill their role in the messaging protocol as follows: -### AVM +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -### CosmWasm +## Guardian Network -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -### Move VM +The Guardian Network is designed to help Wormhole deliver on five key principles: -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -### NEAR VM +The following sections explore each principle in detail. -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Decentralization -### Sui Move VM +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- ---- END CONTENT --- +Two common approaches to decentralization have notable limitations: -Doc-Content: https://wormhole.com/docs/protocol/security/ ---- BEGIN CONTENT --- ---- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics ---- +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -# Security +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -## Core Security Assumptions +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +To answer that, consider these key constraints and design decisions: -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -In summary: +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +### Modularity -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -## Guardian Network +### Chain Agnosticism -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -### Governance +### Scalability -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +### Upgradeable -Via governance, the Guardians can: +Wormhole is designed to adapt and evolve in the following ways: -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. - -## Monitoring - -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. - -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. - -Guardians monitor: - -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators - -## Asset Layer Protections - -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. - -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. - -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. - -## Open Source - -Wormhole builds in the open and is always open source. - -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -## Audits +## Next Steps -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +
-- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +- :octicons-book-16:{ .lg .middle } **Relayers** -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + --- -## Bug Bounties + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + --- -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. -## Learn More + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. categories: Basics --- -# Get Started with Core Contracts - -## Introduction - -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. - -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Core Contract, you'll need the following: - -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on - -## How to Interact with Core Contracts - -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: - -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - -### Sending Messages - -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. - -=== "EVM" - - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: - - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` - - ??? interface "Parameters" - - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. - - --- - - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. - - --- - - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - - ??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" - - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); - -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); - -// Check fee and send parameters - -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); - -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); - -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: - - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` - - ??? interface "Parameters" - - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -2936,245 +2818,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -3358,4 +3086,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index f491d3af1..aca25f23b 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -13,871 +13,266 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md [type: learn] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/learn/transfers/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ --- BEGIN CONTENT --- --- -title: Multichain Transfers -description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -categories: Transfer +title: Integrate Connect into a React DApp Tutorial +description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +categories: Connect, Transfer --- -# Multichain Transfers - -These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. - -Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: - -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset -- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism - -## Compare Transfer Products - -A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: - -### NTT vs. Token Bridge - -Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. - -- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains -- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases - -
- -| Supports | NTT | Token Bridge | -|---------------------------|--------------------|--------------------| -| Message Payload | :white_check_mark: | :white_check_mark: | -| Wrapped Assets | :x: | :white_check_mark: | -| Native Assets | :white_check_mark: | :x: | -| Contract-Free Development | :x: | :white_check_mark: | -| User-Owned Contracts | :white_check_mark: | :x: | - -
- -In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: - -
- - -### Settlement - -Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. +# Integrate Connect into a React DApp -By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} -## Additional Resources +## Introduction -
+In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. -- :octicons-tools-16:{ .lg .middle } **Product Comparison** +While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. - --- +## Prerequisites - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. +Before starting this tutorial, ensure you have the following: - [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use +- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} +- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees -- :octicons-book-16:{ .lg .middle } **Use Cases** +## Set Up Connect for Sui Transfers - --- +### Create a React Project - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +Start by setting up your React app: - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) +1. Open your terminal and run the following command to create a new React app: + ```bash + npx create-react-app connect-tutorial + ``` -
---- END CONTENT --- +2. Navigate into the project directory: -Doc-Content: https://wormhole.com/docs/learn/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Circle's CCTP Bridge -description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -categories: Transfer ---- + ```bash + cd connect-tutorial + ``` -# Circle's CCTP Bridge +### Install Wormhole Connect -Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. +Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: -While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: +```bash +npm install @wormhole-foundation/wormhole-connect +``` -- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves -- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain -- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer +### Integrate Connect into the Application -!!! note - Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. +=== "JavaScript" -## Automatic Relaying + ```js + import logo from './logo.svg'; + import './App.css'; + import WormholeConnect from '@wormhole-foundation/wormhole-connect'; -To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. + const config = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + }; -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. + function App() { + return ; + } -The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. + export default App; + ``` -| Chain | Fee | -|:---------------:|:---------------:| -| Ethereum | 1.0 USDC | -| Everything else | 0.1 USDC | +=== "TypeScript" - + ```ts + import './App.css'; + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + } from '@wormhole-foundation/wormhole-connect'; -## Native Gas Drop Off + function App() { + const config: WormholeConnectConfig = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], -Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. + ui: { + title: 'SUI Connect TS Demo', + }, + }; -The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. + const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + }; - ---- END CONTENT --- + return ; + } -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: A Quick Look at Native Token Transfers -description: This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- + export default App; + ``` -# Native Token Transfers +- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment +- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche -## Get Started +### Customize Wormhole Connect -This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. +To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. -
+### Run the Application -- :octicons-question-16:{ .lg .middle } **Overview** +Make sure you’re in the root directory of your React app, and run the following command to start the application: - --- +```bash +npm start +``` - Dive into an introduction to NTT and discover what NTT is, what its key features are, and the available integration paths. +Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. - [:custom-arrow: Learn more about NTT](/docs/learn/transfers/native-token-transfers/overview/) +## Transfer Tokens from Sui to Fuji -- :octicons-question-16:{ .lg .middle } **Architecture** +Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. - --- +To transfer tokens from Sui to Fuji in the Wormhole Connect interface: - Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. +1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer +2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network +3. Enter the amount of SUI tokens you wish to transfer - [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) -- :octicons-book-16:{ .lg .middle } **Deployment Models** +4. Choose to view other routes + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) - --- +5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) - The NTT framework offers two deployment models for different token management needs: the hub-and-spoke and burn-and-mint models. + !!! note + It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. - [:custom-arrow: Check out the deployment models](/docs/learn/transfers/native-token-transfers/deployment/) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) -- :octicons-shield-lock-16:{ .lg .middle } **Security** +6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain - --- + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) - Explore NTT's security measures, including the Global Accountant and governance strategies for seamless token safety. +7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet - [:custom-arrow: Review the security measures](/docs/learn/transfers/native-token-transfers/security/) + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) -
+Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. -## Next Steps +## Claim Tokens on Fuji -Ready to dive in and start building? Check out the following resources to begin the deployment process and make the most of your deployment. +After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -
+![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) -- :octicons-rocket-16:{ .lg .middle } **Deploy NTT** +Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. - --- +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) - Explore detailed guides that walk you through the entire deployment process, from installing the NTT CLI to deploying NTT across supported chains. +## Resources - [:custom-arrow: Deploy now using the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/) +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. -- :octicons-checklist-16:{ .lg .middle } **Post Deployment Recommendations** +## Conclusion - --- +In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. - Already deployed your NTT project? Check out these post deployment recommendations and integration demos to get the most out of your deployment. +By following these steps, you've learned how to: - [:custom-arrow: Get the most of out your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) +- Set up a React project tailored for cross-chain transfers +- Install and configure Wormhole Connect to support multiple blockchains +- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers +- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks -
+With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +Doc-Content: https://wormhole.com/docs/..build/transfers/cctp/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Architecture -description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. -categories: NTT, Transfer +title: Interacting with CCTP Contracts +description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. +categories: Transfer --- -## Introduction +# Get Started with CCTP -The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. +## Introduction -For the technical implementations of the functions, refer to the [Managers and Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/){target=\_blank} page. +Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. -## System Components +As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. -The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. +This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. -### Managers +## Prerequisites -_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. +To interact with the Wormhole CCTP, you'll need the following: -Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -A manager is responsible for: +## Wormhole's CCTP Integration Contract -- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer -- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers - - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted - - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded +Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). - Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit +The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. -- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed -- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility +This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. -### Transceivers - -_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. - -While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. - -Transceivers are entrusted with several responsibilities: - -- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing -- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer -- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed - -How it works: - -1. The transceiver receives instructions from the manager to send messages across chains -2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred -3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain - -![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) - -!!! note - [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. - -#### Custom Transceivers - -The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. - -NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. - -![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) - -The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. - -For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. - -## Lifecycle of a Message - -The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. - -### Transfer - -The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. - -In both cases: - -- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain -- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain - -Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. - -### Rate Limit - -Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. - -- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error -- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error - -Both chains emit events or logs when transfers are rate-limited or queued. - -### Send - -After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. - -- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message -- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification - -In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. - -### Receive - -Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. - -- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers -- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing - -In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. - -### Mint or Unlock - -Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. - -- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred -- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced - -In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- - -# Deployment Models - -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. - -## Hub-and-Spoke - -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain - -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - -## Burn-and-Mint - -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - -This model best suits new token deployments or projects willing to upgrade existing contracts. - -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- - -# Native Token Transfers - -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - -## Introduction - -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. - -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. - -## Key Features - -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: - -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - -## Integration Paths - -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. - -### Native Token Transfers Framework - -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. - -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: - -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} - -### Token Bridge - -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains - -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. - -## Supported Token Standards - -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/security/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Security -description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -categories: NTT, Transfer ---- - -# Security - -## Global Accountant - -The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. - -This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. - -[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. - -## Governance and Upgradeability - -Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. - -The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: - -- Adding or removing a transceiver address from the registry -- Setting the token contract address on a bridging contract -- Setting the Wormhole Core Contract address on a bridging contract -- Setting the registered bridging contract address on the token contract - -This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement -description: Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. -categories: Settlement, Transfer ---- - -# Wormhole Settlement - -## Get Started - -This section covers Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. - -
- -- :octicons-question-16:{ .lg .middle } **Overview** - - --- - - Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. - - [:custom-arrow: Learn more about Wormhole Settlement](/docs/learn/transfers/settlement/overview/) - -- :octicons-question-16:{ .lg .middle } **Protocol Architectures** - - --- - - Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. - - [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: Settlement Protocol Architecture -description: Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. -categories: Settlement, Transfer ---- - -# Settlement Protocol Architecture - -## Introduction - -This page describes the high-level mechanics of the underlying native swap protocols in the Wormhole SDK. While built on Wormhole messaging, each protocol uses a novel architecture with unique price discovery, scalability, and latency tradeoffs. These designs enable redundancy to handle highly asymmetric flows and sharp volume changes. These sections will cover the following: - -- **Wormhole Liquidity Layer** - a cross-chain transfer protocol that utilizes Solana as the central orchestration layer for cross-chain intents, allowing solvers to deploy liquidity from a single Solana-based hub rather than distributing it across each supported chain -- **Mayan Swift** - a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent -- **Mayan MCTP** - a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains - -## Wormhole Liquidity Layer - -Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster-than-finality transfers across the Wormhole ecosystem through a novel, Solana-based hub-and-spoke architecture. The hub-and-spoke model leverages interoperable token standards like Circle's CCTP (and Wormhole's NTT), allowing the solver to natively mint and burn assets between chains for intent fulfillment. This architecture allows solvers to facilitate cross-chain transfers by fronting assets on the destination chain and assuming the finality risk of the originating source chain transaction. - -Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. - -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) - -The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. - -### Solvers and Liquidity Fragmentation - -Traditional intent-based protocols require solvers to distribute their capital across each supported chain in the network. This liquidity fragmentation leads to capital inefficiency and requires complex rebalancing to manage asymmetric flows between chains. As the number of chains increases, solvers face scalability challenges, which can result in market concentration, reducing competition and potentially impacting price discovery in intent execution. - -Using a hub-and-spoke model, the Wormhole Liquidity Layer solves these challenges by consolidating solver liquidity on a single chain, Solana. This model eliminates the need for complex cross-chain rebalancing and simplifies solvers' infrastructure requirements. Solvers only need to consider the finality risk of the originating source chain transaction and the payload size when bidding on transfers. By concentrating liquidity on Solana, the protocol can handle large transfer volumes with a smaller capital base, enhancing capital efficiency and lowering barriers to entry for solvers. This approach promotes competition, improves overall market efficiency, and ultimately benefits users with better prices while still preserving the speed of transactions. - -### Enable Unified Liquidity - -The novel hub-and-spoke liquidity architecture relies on interoperable token standards that enable cross-chain token fungibility, such as Circle's Cross-Chain Transfer Protocol (CCTP) and Wormhole's Native Token Transfers (NTT). These protocols allow assets to move seamlessly between chains, making unified liquidity possible. On the liquidity hub (Solana), solvers concentrate their liquidity in NTT or CCTP-supported assets, such as USDC. These assets act as the shuttle between chains but may not necessarily be the user's original or final asset. - -After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. - -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. - -### Protocol Flow: How It Works - -1. **Initiation** - users or protocols initiate a transfer via an interface or directly on-chain. They choose between a standard transfer (waiting for finality on the sending chain) or a fast transfer (triggering the auction process). For fast transfers, users or the protocol specify a maximum fee and an auction start deadline - - !!! Note - If an auction doesn't start within the set deadline, a standard transfer will proceed directly from the source to the destination chain. - -2. **Auction** - solvers monitor the Wormhole network for these fast transfer requests and initiate an auction on Solana by offering to fulfill the transfer at or below the user's maximum fee. To start the auction, the solver must transfer the requested funds plus a small security deposit to the Matching Engine contract -3. **Competition** - once initiated, other solvers can participate by submitting lower bids in a simple English auction, aiming to provide users with the best rate. If a new solver submits a better offer, the previous solver's funds and security deposit are returned, with the latest offer taking precedence atomically. This competition ensures that users receive the best possible transfer rate -4. **Fulfillment** - after the auction concludes, the winning solver must complete the transfer within a predefined grace period to earn their fee and reclaim their security deposit. Failure to do so may result in the security deposit being slashed, with the slashed amount compensating the user for delays. This mechanism incentivizes prompt execution. Upon successful completion, the Fast Transfer hub sends the USDC to the user's destination wallet, and the solver receives their security deposit and transfer fee -5. **Settlement** - once the source chain transaction reaches finality, the winning solver can use the finalized Wormhole message to settle the auction with the matching engine and rebalance. This allows the solver to retrieve the original transfer amount into their wallet - -## Mayan Swift - -Mayan Swift is a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent. - -### On-Chain Competitive Price Discovery Mechanism - -Traditional intent-based protocols essentially function as cross-chain limit orders. If the order is profitable, solvers will compete to fulfill it, leading to MEV-like competition focused on speed. While functional, this methodology presents two clear inefficiencies and drawbacks. - -First, they lack a competitive price discovery mechanism as limit order prices are typically determined through centralized off-chain systems. Second, in this MEV-like market structure, only a single solver can win, while the others lose out on transaction fees. This dynamic of deadweight loss results in solvers prioritizing high-margin orders, ultimately resulting in elevated fees for end-users without commensurate benefits. - -Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. - -![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) - -### Protocol Flow: How It Works - -1. **Initiation** - the user creates an order by signing a transaction that locks one of the primary assets (USDC or ETH) into the Mayan smart contract, specifying the desired outcome. - - !!!note - If the input asset is not a primary asset, it is converted into a primary asset within the same transaction before the order is submitted. - - Each order includes properties such as destination chain, destination wallet address, output token address, minimum output amount, gas drop amount, deadline, and 32 bytes of random hex to prevent collisions. A Keccak-256 hash is then calculated to identify the order - -2. **Auction** - solvers observe on-chain data or subscribe to the Mayan explorer web socket (solvers using the Mayan explorer verify the order's integrity by checking the data against the on-chain hash). Once the new order is verified, an on-chain auction on Solana is initiated by passing the order ID and the bid amount, which cannot be lower than the minimum amount. Other solvers can increase the bid by submitting a higher amount before the auction ends -3. **Fulfillment** - the auction ends three seconds after the initial bid. Once the auction ends, the winning solver can execute an instruction that passes their wallet address on the destination chain. This triggers a Wormhole message containing the order ID and the winner's wallet address. Wormhole Guardians then sign this message, allowing the winning solver to fulfill the order on the destination chain by submitting proof of their win and the promised amount to the Mayan contract before the deadline. The Mayan contract deducts a protocol fee (currently 3 basis points) and a referral fee (if applicable), transferring the remaining amount to the user's destination wallet. It also triggers a Wormhole message as proof of fulfillment -4. **Settlement** - after the Wormhole Guardians sign the fulfillment message, the winning solver can submit this message on the source chain to unlock the user's funds and transfer them to their own wallet. Upon fulfillment, the solver has the option to delay triggering a Wormhole message immediately. Instead, they can batch the proofs and, once the batch reaches a certain threshold, issue a batched proof to unlock all orders simultaneously, saving on gas fees - -## Mayan MCTP - -Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. - -![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) - -### Protocol Flow: How It Works - -1. **Initiation** - the user creates an order by signing a transaction that locks one USDC into the Mayan smart contract, specifying the desired outcome. - - !!!note - If the input asset is not USDC, it is converted into a primary asset within the same transaction before the order is submitted. - - The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash - -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} -3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules - -The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. - -## Where to Go Next - -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide -- To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- - -# Wormhole Settlement Overview - -## Introduction - -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - -### How Does It Work? - -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. - -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). - -### Token Transfer Flow - -The transfer process is simple yet secure, involving a few key steps: - -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody - -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) - -### Key Features of the Token Bridge - -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - -### Message and Payload Structure - -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract - -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - -### Security and Authorization - -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - -### Portal Bridge - -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/start-building/products/ ---- BEGIN CONTENT --- ---- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics ---- - -# Products - -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. - -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. - -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. - -## Transfer Products - -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods - -
- -::spantable:: - -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | - -::end-spantable:: - -
- -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. - -## Real-time Data - -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. - -## Multichain Governance - -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Interacting with CCTP Contracts -description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -categories: Transfer ---- - -# Get Started with CCTP - -## Introduction - -Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. - -As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. - -This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. - -## Prerequisites - -To interact with the Wormhole CCTP, you'll need the following: - -- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on - -## Wormhole's CCTP Integration Contract - -Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). - -The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. - -This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. - -!!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. +!!! note + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. ??? code "Circle Integration contract" ```solidity @@ -3467,7 +2862,7 @@ function receivePayloadAndUSDC( To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/ +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ --- BEGIN CONTENT --- --- title: Wormhole Connect @@ -3503,2749 +2898,2806 @@ Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} pag Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) - -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** - - --- - - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - - - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - - -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** - - --- - - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** - - --- - - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect + [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) -## Configure Connect +- :octicons-tools-16:{ .lg .middle } **Multichain Swap** -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. + --- -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. -!!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}. + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) -
-- :octicons-database-16:{ .lg .middle } **Data** +- :octicons-tools-16:{ .lg .middle } **Connect FAQs** --- - Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - + Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [:custom-arrow: Get started](/docs/products/connect/configuration/data/) + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) -- :octicons-apps-16:{ .lg .middle } **Theme** +- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** --- - Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. + Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/) + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/)
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ --- BEGIN CONTENT --- --- -title: Connect Data Configuration -description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +title: Overview +description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. categories: Connect, Transfer --- -## Data Configuration - -This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - -## Get Started - -Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. - -=== "React integration" - - ```ts - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - } -} +# Wormhole Connect - - ``` +## Introduction {: #introduction } -=== "Hosted integration" +Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. - ```ts - import WormholeConnect, { - wormholeConnectHosted, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; +## Features {: #features } -const container = document.getElementById('bridge-container'); +Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -wormholeConnectHosted(container, { - config, -}); - ``` +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) +- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) +- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer +- Ability to configure any token to bridge via Wormhole +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -!!! note - The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. -## Examples {: #examples } +## Integrate Connect {: #integrate-connect } -### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } +### Import Directly into a React App {: #import-directly-into-a-react-app} -Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. +First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} -=== "Mainnet" +```bash +npm i @wormhole-foundation/wormhole-connect +``` - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +Now you can import the React component: -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; +```ts +import WormholeConnect from '@wormhole-foundation/wormhole-connect'; function App() { - return ; + return ; } - ``` +``` -=== "Testnet" +### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. -const config: WormholeConnectConfig = { - // You can use Connect with testnet chains by specifying "network": - network: 'Testnet', - chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], - rpcs: { - Avalanche: 'https://rpc.ankr.com/avalanche_fuji', - BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', - }, -}; +```ts title="v1.x" +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -function App() { - return ; -} - ``` +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); -!!! note - For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. +wormholeConnectHosted(container); +``` -### Configuring Routes +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. -By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. +???- code "v0.x" + Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. -#### Available Route Plugins + ```html + +
+ + + + ``` -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: + For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol + ```html + +
+ + + + ``` -In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. +It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. -For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. +## Configuration {: #configuration} -#### Example: Offer Only CCTP Transfers +This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + - Use custom styles + - Restrict the chains that you allow in your app + - Add support for your project's token, and eliminate tokens you don't want to reduce noise + - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; +For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. +--- END CONTENT --- -; -``` +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers (NTT) +description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. +categories: NTT, Transfer +--- -#### Example: Offer All Default Routes and Third-Party Plugins +# Native Token Transfers -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. -import { myNttConfig } from './consts'; // Custom NTT configuration +## Quickstart -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; +If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. -; -``` +The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. +[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] -### Adding Custom Tokens {: #custom-tokens } +## Deploy NTTs with Launchpad -The following section shows how to add an arbitrary token to your deployment of Connect. +If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -!!! note - You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. -This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. +## Additional Resources -See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. +
-```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** -const config: WormholeConnectConfig = { - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - nativeChain: 'Ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - coinGeckoId: 'bonk', - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; -``` + --- -### Whitelisting Tokens {: #whitelisting-tokens } + The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. -Connect offers a list of built-in tokens by default. You can see it below: + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) -- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} -- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. + --- -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: ['ETH', 'SOL', 'BONK'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) -function App() { - return ; -} -``` +
+--- END CONTENT --- -You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Installation +description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. +categories: NTT, Transfer +--- -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +# Install the Native Token Transfers CLI -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: [ - // Whitelist BONK on every whitelisted chain - 'BONK', - // Also whitelist USDC, specifically on Solana - ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] - ], - ... -}; +In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. -function App() { - return ; -} -``` +To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. -### User-Inputted Tokens {: #user-inputted-tokens } +
-As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). +## Install NTT CLI -If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: +The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +- Install [Bun](https://bun.sh/docs/installation){target=\_blank} -const config: WormholeConnectConfig = { - ui: { - disableUserInputtedTokens: true - } -}; +Follow these steps to install the NTT CLI: -function App() { - return ; -} -``` +1. Run the installation command in your terminal: -Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -### Transaction Settings {: #transaction-settings } +2. Verify the NTT CLI is installed: -Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. + ```bash + ntt --version + ``` -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI -const config: WormholeConnectConfig = { - transactionSettings: { - Solana: { - priorityFee: { - // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. - // For example, you can set percentile to 0.95 to make Connect compute the - // 95th percentile priority fee amount based on recent transactions - percentile: 0.95, +## Update NTT CLI - // Any number, defaults to 1.0. The fee amount is multiplied by this number. - // This can be used to further raise or lower the fees Connect is using. - // For example, percentile=0.95 and percentileMultiple=1.1 would use - // the 95th percentile fee, with a 10% increase - percentileMultiple: 1.1, +To update an existing NTT CLI installation, run the following command in your terminal: - // Minimum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 1 - min: 200_000, +```bash +ntt update +``` - // Maximum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 100,000,000 - max: 5_000_000, - } - } - } -}; +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. -function App() { - return ; -} +For local development, you can update your CLI version from a specific branch or install from a local path. + +To install from a specific branch, run: + +```bash +ntt update --branch foo ``` -!!! note - Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` -### Wallet Set Up {: #reown-cloud-project-id } +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. -Your selected blockchain network determines the available wallet options when using Wormhole Connect. +## Where to Go Next - - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported - - For Solana, you'll see options such as Phantom, Torus, and Coin98 +
-The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. -If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. +- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** -### CoinGecko API Key {: #coingecko-api-key } + --- -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. + Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) -const config: WormholeConnectConfig = { - coinGeckoApiKey: 'INSERT_API_KEY', -}; +- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** -function App() { - return ; -} -``` + --- + + Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. + + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ --- BEGIN CONTENT --- --- -title: Connect Theme & UI Customization -description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. -categories: Connect, Transfer +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer --- -## Theme & UI Customization +# Native Token Transfers Post Deployment -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): -### Changing the Color Scheme +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment -You can customize Connect's color scheme by providing a `theme` prop. +## Manual Relaying for Solana Transfers -=== "React integration" +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. - ```ts - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, -} from '@wormhole-foundation/wormhole-connect'; +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -const config: WormholeConnectConfig = { - /* Your config... */ -}; +[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; +## Where to Go Next -function App() { - return ; -} - ``` +
-=== "Hosted integration" +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** + + --- + + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) + +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** + + --- + + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. + + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) + +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ +--- BEGIN CONTENT --- +--- +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +categories: NTT, Transfer +--- - ```ts - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - wormholeConnectHosted, -} from '@wormhole-foundation/wormhole-connect'; +# Managers and Transceivers -const config: WormholeConnectConfig = { - /* Your config... */ -}; +## Managers -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: -const container = document.getElementById('bridge-container'); +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain -wormholeConnectHosted(container, { - config, - theme, -}); + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) ``` -The `WormholeConnectTheme` type supports the following properties: - -|
Property
| Description | Example | -|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| -| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | -| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | -| `primary` | Primary color used for buttons | `"#AABBCC"` | -| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | -| `text` | Primary color used for text | `"#AABBCC"` | -| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | -| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | -| `success` | Color to display success messages in | `"#AABBCC"` | -| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer -### Toggle Hamburger Menu {: #toggle-hamburger-menu } + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` -By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected -#### Add Extra Menu Entry {: #add-extra-menu-entry } + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner + ``` -By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): +## Transceivers -| Property | Description | -|:--------:|:-------------------------------------------:| -| `label` | Link name to show up | -| `href` | Target URL or URN | -| `target` | Anchor standard target, by default `_blank` | -| `order` | Order where the new item should be injected | +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -const config: WormholeConnectConfig = { - ui: { - showHamburgerMenu: false, - menu: [ - { - label: 'Advance Tools', - href: 'https://portalbridge.com', - target: '_self', - order: 1, - }, - ], - }, -}; + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -function App() { - return ; -} -``` ---- END CONTENT --- +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -Doc-Content: https://wormhole.com/docs/products/connect/faqs/ ---- BEGIN CONTENT --- ---- -title: Connect FAQs -description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -categories: Connect, Transfer ---- + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -# Wormhole Connect FAQs +## Lifecycle of a Message -## What types of assets does Connect support? +### EVM -Wormhole Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: +#### Transfer - - Major stablecoins like USDT and USDC (via CCTP) - - Native gas tokens such as ETH, SOL, etc. - - Cross-chain asset swaps through integrators like Mayan +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. -When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. +**Events** -## What chains does Connect support? +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); +``` -Connect supports around 30 chains, spanning various blockchain runtimes: +#### Rate Limit - - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) - - Solana - - Move-based chains (Sui, Aptos) +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. -For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. -## What is gas dropoff? +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. -Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. -## Can I customize Connect inside my application? +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. -Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. +**Events** -## Which functions or events does Connect rely on for NTT integration? +```ts +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); +``` -Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` -## Do integrators need to enable wallets like Phantom or Backpack in Wormhole Connect? +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` -Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Wormhole Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. +#### Send -## Which function should be modified to set priority fees for Solana transactions? +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). -In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. -To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. +**Events** -The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` -## Is there a minimum amount for bridging with CCTP or the Connect SDK? +#### Receive -There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. -Current relay fees: +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. -- Ethereum L1: ~4.2 USDC -- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. -Additional notes: +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. -- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality -- **Frontend integrations** - - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. - !!!note - The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. ---- END CONTENT --- +**Events** -Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ ---- BEGIN CONTENT --- ---- -title: Features -description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. -categories: Connect, Transfer ---- +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` -## Feature Support Matrix {: #feature-support-matrix} +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` -*Scroll down for details about each column.* +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | -|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| -| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | -| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | -| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | -| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | -| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | -| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | -| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | -| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | -| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | -| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | -| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | -| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | -| Base | ✅ | ✅ | ✅ | ✅ | ✅ | -| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | -| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | -| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | -| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | +#### Mint or Unlock -## Feature Explanation {: #feature-explanation} +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -### Token Bridge {: #token-bridge} +**Events** -Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. +```ts +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); +``` -This route appears if both of the following conditions are satisfied: +### Solana - - Both the origin and destination chains support Token Bridge - - No non-Token Bridge routes are available for the selected token +#### Transfer -### Token Bridge Relayer {: #token-bridge-relayer} +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. -On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. +Depending on the mode and instruction, the following will be produced in the program logs: -This route appears if all of the following conditions are satisfied: +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` -- Both the origin and destination chains support Token Bridge -- Both the origin and destination chains support Token Bridge relayer -- No non-Token Bridge routes are available for the selected token -- The relayer supports the selected token on the origin chain +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. -### Circle CCTP {: #circle-cctp} +#### Rate Limit -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. -This route appears if all of the following conditions are satisfied: +If the transfer amount fits within the current capacity: -- Both the origin and destination chains support Circle CCTP -- The selected token is native Circle-issued USDC +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. -### ETH Bridge {: #eth-bridge} +If the transfer amount doesn't fit within the current capacity: -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -This route appears if all of the following conditions are satisfied: +#### Send -- Both the origin and destination chains support the ETH Bridge -- The selected token is native ETH, wstETH, or canonical wETH +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. -### Gas Drop Off {: #gas-drop-off} +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. -A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. -This route appears if all of the following conditions are satisfied: +The following will be produced in the program logs: -- Both the origin and destination chains support gas drop off -- An automatic route is selected -- The relayer accepts the selected token to swap into the gas token ---- END CONTENT --- +```ts +Program log: Instruction: ReleaseOutbound +``` -Doc-Content: https://wormhole.com/docs/build/transfers/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- +#### Receive -# Wormhole Connect +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. -## Introduction {: #introduction } +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. +The following will be produced in the program logs: -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. +```ts +Program log: Instruction: ReceiveMessage +``` -## Features {: #features } +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: +The following will be produced in the program logs: -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination +```ts +Program log: Instruction: Redeem +``` -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. +#### Mint or Unlock -## Integrate Connect {: #integrate-connect } +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. -### Import Directly into a React App {: #import-directly-into-a-react-app} +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} +Depending on the mode and instruction, the following will be produced in the program logs: -```bash -npm i @wormhole-foundation/wormhole-connect +```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock ``` +--- END CONTENT --- -Now you can import the React component: +Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ +--- BEGIN CONTENT --- +--- +title: Get Started with Token Bridge +description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. +categories: Token-Bridge, Transfer +--- -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; +# Token Bridge -function App() { - return ; -} -``` +## Introduction -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; +## Prerequisites -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); +To interact with the Wormhole Token Bridge, you'll need the following: -wormholeConnectHosted(container); -``` +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. +## How to Interact with Token Bridge Contracts -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. +The primary functions of the Token Bridge contracts revolve around: - ```html - -
- - - - ``` +- **Attesting a token** - registering a new token for cross-chain transfers +- **Transferring tokens** - locking and minting tokens across chains +- **Transferring tokens with a payload** - including additional data with transfers - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: +### Attest a token - ```html - -
- - - - ``` +Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. +The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. -## Configuration {: #configuration} +```solidity +function attestToken( + address tokenAddress, + uint32 nonce +) external payable returns (uint64 sequence); +``` -This is just an overview of what's possible. Check the [Configuration docs](/docs/build/transfers/connect/configuration/){target=\_blank} for details about all the configuration options. +??? interface "Parameters" -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: + `tokenAddress` ++"address"++ + + The contract address of the token to be attested. - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available + --- -For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. ---- END CONTENT --- + `nonce` ++"uint32"++ -Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ ---- BEGIN CONTENT --- ---- -title: Routes -description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -categories: Connect, Transfer ---- + An arbitrary value provided by the caller to ensure uniqueness. -## Routes Overview {: #routes-overview} +??? interface "Returns" -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/build/transfers/connect/configuration/){target=\_blank}. + `sequence` ++"uint64"++ + + A unique identifier for the attestation transaction. -Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. +When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. +You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. -## Token Bridge Routes {: #token-bridge-routes} +### Transfer Tokens -The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. +Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. -#### Manual Route {: #manual-route} +Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. -The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. +```solidity +function transferTokens( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint256 arbiterFee, + uint32 nonce +) external payable returns (uint64 sequence); +``` -#### Automatic Route {: #automatic-route} +??? interface "Parameters" -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. + `token` ++"address"++ + + The address of the token being transferred. -## CCTP Routes (USDC) {: #cctp-routes-usdc} - -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. + --- -Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. + `amount` ++"uint256"++ + The amount of tokens to be transferred. -#### Manual Route {: #manual-route-cctp} + --- -This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -#### Automatic Route {: #automatic-route-cctp} + --- -Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} + --- -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/build/transfers/connect/configuration/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. + `arbiterFee` ++"uint256"++ + Optional fee to be paid to an arbiter for relaying the transfer. -#### Manual Route {: #manual-route-ntt} + --- -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. + `nonce` ++"uint32"++ + A unique identifier for the transaction. -#### Automatic Route {: #automatic-route-ntt} +??? interface "Returns" -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. -## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} +Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). +```solidity +function completeTransfer(bytes memory encodedVm) external; +``` -#### Automatic Route {: #automatic-route-eth} +??? interface "Parameters" -Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. + `encodedVm` ++"bytes memory"++ + + The signed VAA containing the transfer details. -## USDT Bridge Route {: #usdt-bridge-route} +!!!note + - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation + - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. +### Transfer tokens with payload -#### Automatic Route {: #automatic-route-usdt} +While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. -Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. +Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. -## tBTC Route {: #tbtc-route} +```solidity +function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload +) external payable returns (uint64 sequence); +``` -You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). +??? interface "Parameters" -Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. + `token` ++"address"++ + + The address of the token being transferred. -#### Manual Route {: #manual-route-tbtc} + --- -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. ---- END CONTENT --- + `amount` ++"uint256"++ + The amount of tokens to be transferred. -Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect v1.0 Migration Guide -description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -categories: Connect, Transfer ---- + --- -# Wormhole Connect v1.0 Migration Guide + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -## Overview + --- -The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: + --- - - Update to the latest Connect package - - Apply configuration changes to the **`WormholeConnectConfig`** object - - Understand new routing capabilities and plugin options + `nonce` ++"uint32"++ + A unique identifier for the transaction. -These updates ensure better performance and a smoother integration experience. + --- -For complete documentation on the previous version of Wormhole Connect, please refer to the [Wormhole Connect guide](/docs/build/transfers/connect/){target=\_blank}. + `payload` ++"bytes memory"++ + Arbitrary data payload attached to the transaction. -## Update the Connect Package +??? interface "Returns" + + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. -Run the following command in your terminal: +Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. -```bash -npm install @wormhole-foundation/wormhole-connect@^1.0 +```solidity +function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); ``` -This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. - -## Update the `WormholeConnectConfig` Object +??? interface "Parameters" -In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. + `encodedVm` ++"bytes memory"++ -### Summary of Breaking Changes + The signed VAA containing the transfer details. -- Chain names are now capitalized: `solana` → `Solana` -- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` -- `networks` renamed to `chains`, with capitalized names -- `routes` updated to use route plugins -- `nttGroups` removed in favor of route plugin configuration -- `tokensConfig` updated, with a new key `wrappedTokens` added -- Many UI-related properties consolidated under a top-level `ui` key -- `customTheme` and `mode` were removed, replaced by a top-level `theme` property +??? interface "Returns" -These changes are explained in more detail below, with examples for easy reference. + `bytes memory` -### Capitalize Chain Names + The extracted payload data. -In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. +## Source Code References -=== "v0.x" +For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - ethereum: 'INSERT_ETH_RPC_URL', - solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` -=== "v1.x" +- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} +- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - Ethereum: 'INSERT_ETH_RPC_URL', - Solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` +## Portal Bridge -You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. +A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +--- END CONTENT --- -### Rename `env` to `network` +Doc-Content: https://wormhole.com/docs/..learn/transfers/ +--- BEGIN CONTENT --- +--- +title: Multichain Transfers +description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. +categories: Transfer +--- -The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. +# Multichain Transfers -=== "v0.x" +These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. - ```typescript - const config: WormholeConnectConfig = { - env: 'testnet', - }; - ``` -=== "v1.x" +Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: - ```typescript - const config: WormholeConnectConfig = { - network: 'Testnet', - }; - ``` +- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset +- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism -If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. +## Compare Transfer Products -```typescript -// Defaults to Mainnet -const config: WormholeConnectConfig = {}; -``` +A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: -For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. +### NTT vs. Token Bridge -### Rename `networks` to `chains` +Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. -The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. +- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains +- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases -=== "v0.x" +
- ```typescript - const config: WormholeConnectConfig = { - networks: ['solana', 'ethereum'], - }; - ``` -=== "v1.x" +| Supports | NTT | Token Bridge | +|---------------------------|--------------------|--------------------| +| Message Payload | :white_check_mark: | :white_check_mark: | +| Wrapped Assets | :x: | :white_check_mark: | +| Native Assets | :white_check_mark: | :x: | +| Contract-Free Development | :x: | :white_check_mark: | +| User-Owned Contracts | :white_check_mark: | :x: | - ```typescript - const config: WormholeConnectConfig = { - chains: ['Solana', 'Ethereum'], - }; - ``` +
-### Update `routes` to Use Route Plugins +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +
-By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} +### Settlement -For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. +Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. -#### Available `route` Plugins +By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: +## Additional Resources -???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route - - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - - **`CCTPRoute`** - manually redeemed CCTP route - - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route - - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) - - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route - - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route - - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array - - **`MayanRoute`** - route that offers multiple Mayan protocols - - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only - - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only - - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol +
-In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. +- :octicons-tools-16:{ .lg .middle } **Product Comparison** -For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. + --- -Now that you know the available `route` plugins, let's explore some examples of configuring them. + Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -#### Example: Offer Only CCTP Transfers + [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +- :octicons-book-16:{ .lg .middle } **Use Cases** -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + --- -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; + Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -; -``` + [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) -#### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +
+--- END CONTENT --- -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +Doc-Content: https://wormhole.com/docs/..learn/transfers/cctp/ +--- BEGIN CONTENT --- +--- +title: Circle's CCTP Bridge +description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. +categories: Transfer +--- -import { myNttConfig } from './consts'; // Custom NTT configuration +# Circle's CCTP Bridge -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; +Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. -; -``` +While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. +- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves +- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain +- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer -### Update the `tokensConfig` Structure +!!! note + Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. -Key Changes to `tokensConfig`: +## Automatic Relaying - - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK - - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes - - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain +To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. -=== "v0.x" +This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. - In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. +The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; +| Chain | Fee | +|:---------------:|:---------------:| +| Ethereum | 1.0 USDC | +| Everything else | 0.1 USDC | - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: { Ethereum: 18, default: 8 }, - foreignAssets: { - Solana: { - address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - decimals: 8, - }, - }, - }, - }, - }; - ``` -=== "v1.x" + - In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. +## Native Gas Drop Off - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; +Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'Ethereum', // Chain name now capitalized - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: 18, // Simplified decimals field - }, - }, - wrappedTokens: { - WETH: { - Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - /* additional chains */ - }, - }, - }; - ``` +The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. -### Update NTT Configuration + +--- END CONTENT --- -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers - Deployment Models +description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. +categories: NTT, Transfer +--- -Key changes: +# Deployment Models - - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function - - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers +The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. -This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. +## Hub-and-Spoke -=== "v0.x" +The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. +This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; +- **Hub chain** - tokens are locked when initiating a transfer +- **Spoke chains** - Equivalent tokens are minted on the destination chain - const config: WormholeConnectConfig = { - nttGroups: { - Lido_wstETH: { - nttManagers: [ - { - chainName: 'ethereum', - address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chainName: 'bsc', - address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }, - }; - ``` -=== "v1.x" +When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. +## Burn-and-Mint - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; +The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - const config: WormholeConnectConfig = { - routes: [ - ...nttRoutes({ - tokens: { - Lido_wstETH: [ - { - chain: 'Ethereum', - manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', - transceiver: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chain: 'Bsc', - manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', - transceiver: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }), - /* other routes */ - ], - }; - ``` +This model best suits new token deployments or projects willing to upgrade existing contracts. + +- **Source chain** - tokens are burned when initiating a transfer +- **Destination chain** - equivalent tokens are minted on the destination chain +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Overview +description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. +categories: NTT, Transfer +--- + +# Native Token Transfers + +!!!tip "Looking to deploy NTT?" + If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. + + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. +## Introduction -### Update UI Configuration +Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. +The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. -Key UI changes: +## Key Features - - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization - - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes +Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: -#### UI Properties +- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens +- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience +- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk +- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts +- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains +- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted +- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner +- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols +- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds -The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: +## Integration Paths - - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions - - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token - - `pageHeader` → `ui.pageHeader` - sets the title and header for the page - - `menu` → `ui.menu` - defines the menu items displayed in the interface - - `searchTx` → `ui.searchTx` - configures the transaction search functionality - - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface - - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI - - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation +Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. -Additionally, there are two new properties under `ui`: +### Native Token Transfers Framework - - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" - - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel +The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. -```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model +- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant +- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain +- **Token contracts** - native contracts owned by your protocol governance +- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments -const config: WormholeConnectConfig = { - ui: { - title: 'My Custom Bridge Example', - getHelpUrl: 'https://examplehelp.com/', - menu: [ - { - label: 'Support', - href: 'https://examplehelp.com/support', - target: '_blank', - order: 1, // Order of appearance in the menu - }, - { - label: 'About', - href: 'https://examplehelp.com/about', - target: '_blank', - order: 2, - }, - ], - showHamburgerMenu: false, - }, -}; -``` +The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: -#### UI Configuration +- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} +- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} -In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. +### Token Bridge -=== "v0.x" +The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - ```typescript - const config: WormholeConnectConfig = { - bridgeDefaults: { - fromNetwork: 'solana', - toNetwork: 'ethereum', - tokenKey: 'USDC', - requiredNetwork: 'solana', - }, - showHamburgerMenu: true, - }; - ``` -=== "v1.x" +- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract +- **Security** - preconfigured rate limiting and integrated Global Accountant +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} +- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process +- **Integration** - straightforward and permissionless method to deploy on multiple chains - ```typescript - const config: WormholeConnectConfig = { - ui: { - defaultInputs: { - fromChain: 'Solana', // Chain names now capitalized - toChain: 'Ethereum', - tokenKey: 'USDC', - requiredChain: 'Solana', - }, - showHamburgerMenu: true, - }, - }; - ``` +!!! note + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. -#### Remove `customTheme` and `mode` Properties +## Supported Token Standards -In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. +Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. +--- END CONTENT --- -Important details: +Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Overview +description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +categories: Settlement, Transfer +--- - - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect - - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes +# Wormhole Settlement Overview -=== "v0.x" +## Introduction - ```typescript - const config: WormholeConnectConfig = { - customTheme: { - primaryColor: '#4266f5', - secondaryColor: '#ff5733', - }, - mode: 'dark', - }; +Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - ; - ``` -=== "v1.x" +With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - ```typescript - const theme: WormholeConnectTheme = { - mode: 'dark', // Can be dynamically changed - font: 'Arial', - button: { - primary: '#4266f5', - }, - }; +The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - ; - ``` +Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. -### Removed Configuration Properties +## Key Features -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. +- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well +- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency +- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake -Removed config keys: +## Integrator Paths - - `cta` - - `cctpWarning` - - `pageSubHeader` - - `moreTokens` - - `moreChains` - - `ethBridgeMaxAmount` - - `wstETHBridgeMaxAmount` - - `customTheme` - - `mode` +### SDK Integrators -If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. +Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. -## Use the CDN-Hosted Version of Wormhole Connect +### NTT Integrators -For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. +NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. -### Install and Integrate the Hosted Version +### Chain Integrators -1. Install the Connect package via npm: +Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - ```bash - npm install @wormhole-foundation/wormhole-connect@^1.0 - ``` +!!!tip + Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: +## Related Resources - ```typescript - import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page +--- END CONTENT --- - const container = document.getElementById('connect')!; +Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ +--- BEGIN CONTENT --- +--- +title: Token Bridge +description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. +categories: Token-Bridge, Transfer +--- - wormholeConnectHosted(container); - ``` +# Token Bridge -### Example: Custom Configuration for Hosted Version +Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. -The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: +Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. -```typescript -import { - wormholeConnectHosted, - MayanRoute, -} from '@wormhole-foundation/wormhole-connect'; +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. -const container = document.getElementById('connect')!; +This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. -wormholeConnectHosted(container, { - config: { - routes: [MayanRoute], - eventHandler: (e) => { - console.log('Connect event', e); - }, - }, - theme: { - background: { - default: '#004547', - }, - }, -}); -``` +### How Does It Work? -In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). ---- END CONTENT --- +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. + +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. + +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). + +### Token Transfer Flow + +The transfer process is simple yet secure, involving a few key steps: + +1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message +4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody + +![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) + +### Key Features of the Token Bridge + +The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. -# Native Token Transfers +The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. +### Message and Payload Structure -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. +To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. -## Quickstart +- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens +- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain +- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name +- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain +- `UpgradeContract` - upgrade the contract -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: +One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] +### Security and Authorization -## Deploy NTTs with Launchpad +The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +### Portal Bridge -## Additional Resources +A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ +--- BEGIN CONTENT --- +--- +title: Routes +description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +categories: Connect, Transfer +--- -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** +## Routes Overview {: #routes-overview} - --- +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. +Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +## Token Bridge Routes {: #token-bridge-routes} - --- +The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +#### Manual Route {: #manual-route} - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. -
---- END CONTENT --- +#### Automatic Route {: #automatic-route} -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ ---- BEGIN CONTENT --- ---- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer ---- +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. -# NTT CLI Commands +## CCTP Routes (USDC) {: #cctp-routes-usdc} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. -## Introduction +Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. +#### Manual Route {: #manual-route-cctp} -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](/docs/build/transfers/native-token-transfers/deployment-process/installation/#installation){target=\_blank} to set it up before proceeding. +This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. -## Table of Commands +#### Automatic Route {: #automatic-route-cctp} -The following table lists the available NTT CLI commands, descriptions, and examples. +Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} -### General Commands +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | +#### Manual Route {: #manual-route-ntt} -### Configuration Commands +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| +#### Automatic Route {: #automatic-route-ntt} -### Solana Commands +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| +## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} -## Where to Go Next +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). -
+#### Automatic Route {: #automatic-route-eth} +Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. -- :octicons-gear-16:{ .lg .middle } **Configure NTT** +## USDT Bridge Route {: #usdt-bridge-route} - --- +Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +#### Automatic Route {: #automatic-route-usdt} - [:custom-arrow: Configure your NTT deployment](/docs/build/transfers/native-token-transfers/configuration/) +Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +## tBTC Route {: #tbtc-route} - --- +You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +#### Manual Route {: #manual-route-tbtc} -
+This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- -title: Native Token Transfers (NTT) - Configuration -description: This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -categories: NTT, Transfer +title: Connect Data Configuration +description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +categories: Connect, Transfer --- -# Configure Native Token Transfers (NTT) +## Data Configuration + +This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. ## Get Started -This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. -
+=== "React integration" -- :octicons-clock-16:{ .lg .middle } **Rate Limiting** + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - --- +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + } +} - Discover options for configuring rate limits and how queueing effects transaction flow. + + ``` - [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) +=== "Hosted integration" -- :octicons-unlock-16:{ .lg .middle } **Access Control** + ```ts + import WormholeConnect, { + wormholeConnectHosted, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - --- +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; - Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. +const container = document.getElementById('bridge-container'); - [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) +wormholeConnectHosted(container, { + config, +}); + ``` -
---- END CONTENT --- +!!! note + The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Access Control -description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. -categories: NTT, Transfer ---- +## Examples {: #examples } -## Owner and Pauser Roles +### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } -Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). +Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. -NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. +=== "Mainnet" -- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused -- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; -```json -{ - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": true, // set to true to pause the contract - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - //... - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } +function App() { + return ; } -``` + ``` + +=== "Testnet" + + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + // You can use Connect with testnet chains by specifying "network": + network: 'Testnet', + chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], + rpcs: { + Avalanche: 'https://rpc.ankr.com/avalanche_fuji', + BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', + }, +}; + +function App() { + return ; +} + ``` + +!!! note + For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. + +### Configuring Routes + +By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. + +#### Available Route Plugins + +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -!!! note - While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route +- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route +- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol -The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. +In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. -Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. ---- END CONTENT --- +For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Rate Limiting -description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. -categories: NTT, Transfer ---- +#### Example: Offer Only CCTP Transfers -## Introduction +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: -The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. +```typescript +import WormholeConnect, { + AutomaticCCTPRoute, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], +}; -You can configure the following limits on every chain where NTT is deployed directly using the manager: +; +``` -- **Sending limit** - a single outbound limit for sending tokens from the chain -- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum +#### Example: Offer All Default Routes and Third-Party Plugins -Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -## Update Rate Limits +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -To configure or update the sending and receiving rate limits, follow these steps: +import { myNttConfig } from './consts'; // Custom NTT configuration -1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; -2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed +; +``` - ```json - "limits": { - "outbound": "1000.000000000000000000", - "inbound": { - "Ethereum": "100.000000000000000000", - "Arbitrum": "50.000000000000000000" - } - } - ``` +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. - - **`outbound`** - sets the maximum tokens allowed to leave the chain - - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains +### Adding Custom Tokens {: #custom-tokens } -3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain +The following section shows how to add an arbitrary token to your deployment of Connect. - ```bash - ntt push - ``` +!!! note + You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. -4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status +This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. - ```bash - ntt status - ``` +See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. -???- note "`deployment.json` example" - ```json - { - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": false, - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", - "transceivers": { - "threshold": 1, - "wormhole": { - "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - }, - "limits": { - "outbound": "184467440737.095516150000000000", - "inbound": { - "ArbitrumSepolia": "500.000000000000000000" - } - }, - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } - } - ``` +```typescript +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -## Queuing Mechanism +const config: WormholeConnectConfig = { + tokensConfig: { + BONK: { + key: 'BONK', + symbol: 'BONK', + nativeChain: 'Ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', + }, + coinGeckoId: 'bonk', + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', + }, + }, +}; +``` -When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: +### Whitelisting Tokens {: #whitelisting-tokens } -- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer -- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain +Connect offers a list of built-in tokens by default. You can see it below: -Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. +- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} +- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} -## Cancel Flows +You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. -If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. ---- END CONTENT --- +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) - Deployment -description: This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. -categories: NTT, Transfer ---- +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Solana'], + tokens: ['ETH', 'SOL', 'BONK'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, + tokensConfig: { + BONK: { + key: 'BONK', + symbol: 'BONK', + icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', + tokenId: { + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', + }, + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', + }, + }, +}; + +function App() { + return ; +} +``` -# Deploy Native Token Transfers (NTT) +You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. -## Get Started +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Solana'], + tokens: [ + // Whitelist BONK on every whitelisted chain + 'BONK', + // Also whitelist USDC, specifically on Solana + ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] + ], + ... +}; -This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. +function App() { + return ; +} +``` -
+### User-Inputted Tokens {: #user-inputted-tokens } -- :octicons-download-16:{ .lg .middle } **Installation** +As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). - --- +If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: - Prerequisites and commands for installing the NTT CLI and working with the NTT framework. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - [:custom-arrow: Install the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/) +const config: WormholeConnectConfig = { + ui: { + disableUserInputtedTokens: true + } +}; -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** +function App() { + return ; +} +``` - --- +Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. - Find information on preparing for NTT deployment to EVM, including an example NTT token repository. +### Transaction Settings {: #transaction-settings } - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) +Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - --- +const config: WormholeConnectConfig = { + transactionSettings: { + Solana: { + priorityFee: { + // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. + // For example, you can set percentile to 0.95 to make Connect compute the + // 95th percentile priority fee amount based on recent transactions + percentile: 0.95, - Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. + // Any number, defaults to 1.0. The fee amount is multiplied by this number. + // This can be used to further raise or lower the fees Connect is using. + // For example, percentile=0.95 and percentileMultiple=1.1 would use + // the 95th percentile fee, with a 10% increase + percentileMultiple: 1.1, - [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) + // Minimum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 1 + min: 200_000, -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** + // Maximum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 100,000,000 + max: 5_000_000, + } + } + } +}; - --- +function App() { + return ; +} +``` - Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +!!! note + Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) +### Wallet Set Up {: #reown-cloud-project-id } -- :octicons-search-16:{ .lg .middle } **Post Deployment** +Your selected blockchain network determines the available wallet options when using Wormhole Connect. - --- + - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported + - For Solana, you'll see options such as Phantom, Torus, and Coin98 - Learn how to best monitor and maintain your NTT deployment to get the most out of your Wormhole integration while providing security for users. +The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. - [:custom-arrow: Explore next steps](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) +If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. -- :octicons-alert-16:{ .lg .middle } **Troubleshooting** +### CoinGecko API Key {: #coingecko-api-key } - --- +The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. - Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) +const config: WormholeConnectConfig = { + coinGeckoApiKey: 'INSERT_API_KEY', +}; -
+function App() { + return ; +} +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ --- BEGIN CONTENT --- --- -title: Native Token Transfers EVM Deployment -description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer +title: Connect Theme & UI Customization +description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. +categories: Connect, Transfer --- -# Native Token Transfers (NTT) EVM Development - -## Deploy Your Token and Ensure Compatibility - -If you still need to do so, deploy the token contract to the destination or spoke chains. +## Theme & UI Customization -### Requirements for Token Deployment +This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +### Changing the Color Scheme -#### Burn-and-Mint Mode +You can customize Connect's color scheme by providing a `theme` prop. -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: +=== "React integration" -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` + ```ts + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. +const config: WormholeConnectConfig = { + /* Your config... */ +}; -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', +}; -interface INttToken { - /// @notice Error when the caller is not the minter. - /// @dev Selector 0x5fb5729e. - /// @param caller The caller of the function. - error CallerNotMinter(address caller); +function App() { + return ; +} + ``` - /// @notice Error when the minter is the zero address. - /// @dev Selector 0x04a208c7. - error InvalidMinterZeroAddress(); +=== "Hosted integration" - /// @notice Error when insufficient balance to burn the amount. - /// @dev Selector 0xcf479181. - /// @param balance The balance of the account. - /// @param amount The amount to burn. - error InsufficientBalance(uint256 balance, uint256 amount); + ```ts + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; - /// @notice The minter has been changed. - /// @dev Topic0 - /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. - /// @param newMinter The new minter. - event NewMinter(address previousMinter, address newMinter); +const config: WormholeConnectConfig = { + /* Your config... */ +}; - // NOTE: the `mint` method is not present in the standard ERC20 interface. - function mint(address account, uint256 amount) external; +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', +}; - // NOTE: the `setMinter` method is not present in the standard ERC20 interface. - function setMinter(address newMinter) external; +const container = document.getElementById('bridge-container'); - // NOTE: NttTokens in `burn` mode require the `burn` method to be present. - // This method is not present in the standard ERC20 interface, but is - // found in the `ERC20Burnable` interface. - function burn(uint256 amount) external; -} +wormholeConnectHosted(container, { + config, + theme, +}); ``` -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - -#### Hub-and-Spoke Mode - -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. - - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers +The `WormholeConnectTheme` type supports the following properties: -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +|
Property
| Description | Example | +|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| +| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | +| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | +| `primary` | Primary color used for buttons | `"#AABBCC"` | +| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | +| `text` | Primary color used for text | `"#AABBCC"` | +| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | +| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | +| `success` | Color to display success messages in | `"#AABBCC"` | +| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. +### Toggle Hamburger Menu {: #toggle-hamburger-menu } -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. +By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. -For more detailed information, see the [Deployment Models](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank} page. +#### Add Extra Menu Entry {: #add-extra-menu-entry } -### Key Differences Between Modes +By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +| Property | Description | +|:--------:|:-------------------------------------------:| +| `label` | Link name to show up | +| `href` | Target URL or URN | +| `target` | Anchor standard target, by default `_blank` | +| `order` | Order where the new item should be injected | -## Deploy NTT +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Create a new NTT project: +const config: WormholeConnectConfig = { + ui: { + showHamburgerMenu: false, + menu: [ + { + label: 'Advance Tools', + href: 'https://portalbridge.com', + target: '_self', + order: 1, + }, + ], + }, +}; -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment +function App() { + return ; +} ``` +--- END CONTENT --- -Initialize a new `deployment.json` file specifying the network: +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ +--- BEGIN CONTENT --- +--- +title: Connect FAQs +description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +categories: Connect, Transfer +--- -=== "Testnet" +# Wormhole Connect FAQs - ```bash - ntt init Testnet - ``` +## What types of assets does Connect support? -=== "Mainnet" +Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: - ```bash - ntt init Mainnet - ``` + - Major stablecoins like USDT and USDC (via CCTP) + - Native gas tokens such as ETH, SOL, etc. + - Cross-chain asset swaps through integrators like Mayan -Ensure you have set up your environment correctly: +When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. -```bash -export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY -``` +## What chains does Connect support? -Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: +Connect supports around 30 chains, spanning various blockchain runtimes: -```bash -# Set scanner API Keys as environment variables -export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY -export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY + - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) + - Solana + - Move-based chains (Sui, Aptos) -# Add each chain -# The contracts will be automatically verified using the scanner API keys above -ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -``` +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. -While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. +## What is gas dropoff? -The `ntt add-chain` command takes the following parameters: +Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. -- Name of each chain -- Version of NTT to deploy (use `--latest` for the latest contract versions) -- Mode (either `burning` or `locking`) -- Your token contract address +## Can I customize Connect inside my application? -The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. +Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. -## Configure NTT +## Which functions or events does Connect rely on for NTT integration? -The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: +Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. -- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain -- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: +## Do integrators need to enable wallets like Phantom or Backpack in Connect? + +Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. - For Solana, the limits are set with 9 decimal places: - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - } - ``` +## Which function should be modified to set priority fees for Solana transactions? - For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: - ```json - "inbound": { - "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia - } - ``` +In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. - This initial configuration ensures that the rate limits are correctly represented for each chain's token precision - -- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file +To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. -After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. +The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. -## Set Token Minter to NTT Manager +## Is there a minimum amount for bridging with CCTP or the Connect SDK? -The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. +There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. -!!! note - The required NTT Manager address can be found in the `deployment.json` file. +Current relay fees: -- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function - ```json - cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL - ``` +- Ethereum L1: ~4.2 USDC +- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC -- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter +Additional notes: -By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. +- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality +- **Frontend integrations** + - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} + - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs -!!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. + !!!note + The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Solana Deployment -description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer +title: Wormhole Connect v1.0 Migration Guide +description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. +categories: Connect, Transfer --- -# Deploy Native Token Transfers on Solana +# Wormhole Connect v1.0 Migration Guide -[Native Token Transfers (NTT)](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. +## Overview -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. +This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: -## Prerequisites + - Update to the latest Connect package + - Apply configuration changes to the **`WormholeConnectConfig`** object + - Understand new routing capabilities and plugin options -Before deploying NTT on Solana, ensure you have the following: +These updates ensure better performance and a smoother integration experience. -- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} -- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** -- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +## Update the Connect Package -Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. +To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. -## Overview of the Deployment Process +Run the following command in your terminal: -Deploying NTT with the CLI on Solana follows a structured process: +```bash +npm install @wormhole-foundation/wormhole-connect@^1.0 +``` -1. **Choose your token setup**: +This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. - - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section - - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT +## Update the `WormholeConnectConfig` Object - ???- interface "Create and Mint SPL Tokens" - This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. +In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. - 1. **Generate a Solana key pair** - run the following command to create a new wallet: +### Summary of Breaking Changes - ```bash - solana-keygen grind --starts-with w:1 --ignore-case - ``` +- Chain names are now capitalized: `solana` → `Solana` +- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` +- `networks` renamed to `chains`, with capitalized names +- `routes` updated to use route plugins +- `nttGroups` removed in favor of route plugin configuration +- `tokensConfig` updated, with a new key `wrappedTokens` added +- Many UI-related properties consolidated under a top-level `ui` key +- `customTheme` and `mode` were removed, replaced by a top-level `theme` property - 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: +These changes are explained in more detail below, with examples for easy reference. - ```bash - solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON - ``` +### Capitalize Chain Names - 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: +In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. - === "Mainnet" - ```bash - solana config set -um - ``` +=== "v0.x" - === "Testnet" - ```bash - solana config set -ut - ``` + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + ethereum: 'INSERT_ETH_RPC_URL', + solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` +=== "v1.x" - === "Devnet" - ```bash - solana config set -ud - ``` + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + Ethereum: 'INSERT_ETH_RPC_URL', + Solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` - 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: +You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. - ```bash - solana airdrop 2 - solana balance - ``` +### Rename `env` to `network` - 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} +The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. - ```bash - cargo install spl-token-cli - ``` +=== "v0.x" - 6. **Create a new SPL token** - initialize the token on Solana + ```typescript + const config: WormholeConnectConfig = { + env: 'testnet', + }; + ``` +=== "v1.x" - ```bash - spl-token create-token - ``` + ```typescript + const config: WormholeConnectConfig = { + network: 'Testnet', + }; + ``` - 7. **Create a token account** - generate an account to hold the token +If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. - ```bash - spl-token create-account INSERT_TOKEN_ADDRESS - ``` +```typescript +// Defaults to Mainnet +const config: WormholeConnectConfig = {}; +``` - 8. **Mint tokens** - send 1000 tokens to the created account +For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. - ```bash - spl-token mint INSERT_TOKEN_ADDRESS 1000 - ``` +### Rename `networks` to `chains` - !!! note - NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. +The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. -2. **Choose your [deployment model](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank}**: +=== "v0.x" - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + ```typescript + const config: WormholeConnectConfig = { + networks: ['solana', 'ethereum'], + }; + ``` +=== "v1.x" -3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode + ```typescript + const config: WormholeConnectConfig = { + chains: ['Solana', 'Ethereum'], + }; + ``` -Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. +### Update `routes` to Use Route Plugins -By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. +The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -## Set Up NTT +By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: -To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. + - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} + - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} -The [NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. -1. **Create a new NTT project** - set up a deployment workspace +#### Available `route` Plugins - ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME - ``` +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +???- tip "`route` Plugins" + - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route + - **`CCTPRoute`** - manually redeemed CCTP route + - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route + - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) + - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route + - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route + - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array + - **`MayanRoute`** - route that offers multiple Mayan protocols + - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only + - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only + - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol - === "Mainnet" +In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. - ```bash - ntt init Mainnet - ``` +For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. - === "Testnet" +Now that you know the available `route` plugins, let's explore some examples of configuring them. - ```bash - ntt init Testnet - ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. +#### Example: Offer Only CCTP Transfers -### Set Mint Authority +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: + +```typescript +import WormholeConnect, { + AutomaticCCTPRoute, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], +}; + +; +``` -If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. +#### Example: Offer All Default Routes and Third-Party Plugins -If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Follow these steps to set the mint authority using the NTT CLI: +import { myNttConfig } from './consts'; // Custom NTT configuration -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +; +``` -2. **Derive the token authority** - generate the PDA, which will manage token minting +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. - ```bash - ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR - ``` +### Update the `tokensConfig` Structure -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. - ```bash - spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA - ``` +Key Changes to `tokensConfig`: -## Deploy and Configure NTT + - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK + - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes + - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain -After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: +=== "v0.x" -1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: + In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. - === "Burn-and-Mint" + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; - ```bash - ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: { Ethereum: 18, default: 8 }, + foreignAssets: { + Solana: { + address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + decimals: 8, + }, + }, + }, + }, + }; + ``` +=== "v1.x" - === "Hub-and-Spoke" + In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. - ```bash - ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'Ethereum', // Chain name now capitalized + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: 18, // Simplified decimals field + }, + }, + wrappedTokens: { + WETH: { + Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + /* additional chains */ + }, + }, + }; + ``` -2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: +### Update NTT Configuration - ```bash - ntt status - ``` +In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. - If needed, sync your local configuration with the on-chain state: +Key changes: - ```bash - ntt pull - ``` + - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function + - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers -3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. +This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. - Open your `deployment.json` file and adjust the values based on your use case: +=== "v0.x" - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - }, - "outbound": { - "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia - } - ``` + In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. -4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees + ```typescript + import WormholeConnect, { + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; - ```bash - ntt push --payer INSERT_YOUR_KEYPAIR_JSON + const config: WormholeConnectConfig = { + nttGroups: { + Lido_wstETH: { + nttManagers: [ + { + chainName: 'ethereum', + address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chainName: 'bsc', + address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }, + }; ``` +=== "v1.x" -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. + In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. -## Where to Go Next + ```typescript + import WormholeConnect, { + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -
+ const config: WormholeConnectConfig = { + routes: [ + ...nttRoutes({ + tokens: { + Lido_wstETH: [ + { + chain: 'Ethereum', + manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', + transceiver: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chain: 'Bsc', + manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', + transceiver: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }), + /* other routes */ + ], + }; + ``` -- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** + In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. - --- +### Update UI Configuration - After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. +In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +Key UI changes: -- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** + - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization + - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes - --- +#### UI Properties - Follow the NTT Post Deployment Guide for integration examples and testing instructions. +The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: + + - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions + - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token + - `pageHeader` → `ui.pageHeader` - sets the title and header for the page + - `menu` → `ui.menu` - defines the menu items displayed in the interface + - `searchTx` → `ui.searchTx` - configures the transaction search functionality + - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface + - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI + - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation - [:custom-arrow: Test Your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} +Additionally, there are two new properties under `ui`: -- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** + - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" + - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel - --- +```typescript +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. +const config: WormholeConnectConfig = { + ui: { + title: 'My Custom Bridge Example', + getHelpUrl: 'https://examplehelp.com/', + menu: [ + { + label: 'Support', + href: 'https://examplehelp.com/support', + target: '_blank', + order: 1, // Order of appearance in the menu + }, + { + label: 'About', + href: 'https://examplehelp.com/about', + target: '_blank', + order: 2, + }, + ], + showHamburgerMenu: false, + }, +}; +``` - [:custom-arrow: Use Connect to Integrate NTT](/docs/build/transfers/connect/){target=\_blank} +#### UI Configuration -
---- END CONTENT --- +In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ ---- BEGIN CONTENT --- ---- -title: Deploy Native Token Transfers with Launchpad -description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -categories: NTT, Transfer ---- +=== "v0.x" -# Deploy Native Token Transfers with Launchpad + ```typescript + const config: WormholeConnectConfig = { + bridgeDefaults: { + fromNetwork: 'solana', + toNetwork: 'ethereum', + tokenKey: 'USDC', + requiredNetwork: 'solana', + }, + showHamburgerMenu: true, + }; + ``` +=== "v1.x" -## Introduction + ```typescript + const config: WormholeConnectConfig = { + ui: { + defaultInputs: { + fromChain: 'Solana', // Chain names now capitalized + toChain: 'Ethereum', + tokenKey: 'USDC', + requiredChain: 'Solana', + }, + showHamburgerMenu: true, + }, + }; + ``` -The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. +#### Remove `customTheme` and `mode` Properties -Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. +In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. -The Launchpad automates deployment, reducing complexity and saving time. +Important details: -This guide covers: + - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect + - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes - - Launching a new cross-chain token - - Expanding an existing token for NTT - - Managing tokens via the dashboard and settings +=== "v0.x" -## Prerequisites + ```typescript + const config: WormholeConnectConfig = { + customTheme: { + primaryColor: '#4266f5', + secondaryColor: '#ff5733', + }, + mode: 'dark', + }; - - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) - - Minimum ETH (or equivalent) for gas fees per deployment + ; + ``` +=== "v1.x" -## Supported Blockchains + ```typescript + const theme: WormholeConnectTheme = { + mode: 'dark', // Can be dynamically changed + font: 'Arial', + button: { + primary: '#4266f5', + }, + }; -The NTT Launchpad currently supports deployments on the following mainnet chains: + ; + ``` - - Ethereum - - Arbitrum One - - Base - - Berachain - - Blast - - BNB Smart Chain - - Ink - - Optimism Mainnet - - Polygon +### Removed Configuration Properties -## Choose Your Path +Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. -Once ready, choose an option to proceed: +Removed config keys: - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + - `cta` + - `cctpWarning` + - `pageSubHeader` + - `moreTokens` + - `moreChains` + - `ethBridgeMaxAmount` + - `wstETHBridgeMaxAmount` + - `customTheme` + - `mode` -## Launch a Cross-Chain Token +If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. -Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: +## Use the CDN-Hosted Version of Wormhole Connect -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** +For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) - -2. Select **Launch a Cross-Chain Token** +### Install and Integrate the Hosted Version - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) +1. Install the Connect package via npm: -3. Set the token details: - 1. Select the **home network** from the dropdown menu - 2. Enter the **name** for the token - 3. Enter the **symbol** of the token - 4. Provide the **initial supply** - 5. To the token details, click **Next** + ```bash + npm install @wormhole-foundation/wormhole-connect@^1.0 + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) +2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: -4. Select the deployment chains: - 1. The home network where your token will be deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** + ```typescript + import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) + const container = document.getElementById('connect')!; -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + wormholeConnectHosted(container); + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) +### Example: Custom Configuration for Hosted Version -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) +```typescript +import { + wormholeConnectHosted, + MayanRoute, +} from '@wormhole-foundation/wormhole-connect'; -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +const container = document.getElementById('connect')!; -8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. +wormholeConnectHosted(container, { + config: { + routes: [MayanRoute], + eventHandler: (e) => { + console.log('Connect event', e); + }, + }, + theme: { + background: { + default: '#004547', + }, + }, +}); +``` -## Expand Your Existing Token +In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). +--- END CONTENT --- -Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ +--- BEGIN CONTENT --- +--- +title: Features +description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. +categories: Connect, Transfer +--- -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** +## Feature Support Matrix {: #feature-support-matrix} - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) +*Scroll down for details about each column.* -2. Select **Expand Your Existing Token** +| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | +|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| +| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | +| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | +| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | +| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | +| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | +| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | +| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | +| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | +| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | +| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | +| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | +| Base | ✅ | ✅ | ✅ | ✅ | ✅ | +| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | +| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | +| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | +| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) +## Feature Explanation {: #feature-explanation} -3. Enter the token details: - 1. Choose the home network where your token is already deployed (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** +### Token Bridge {: #token-bridge} - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) +Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. -4. Select the chains to deploy your token to: - 1. The home network where your token is already deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 1. Click **Next** +This route appears if both of the following conditions are satisfied: - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + - Both the origin and destination chains support Token Bridge + - No non-Token Bridge routes are available for the selected token -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction +### Token Bridge Relayer {: #token-bridge-relayer} - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) +This route appears if all of the following conditions are satisfied: -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +- Both the origin and destination chains support Token Bridge +- Both the origin and destination chains support Token Bridge relayer +- No non-Token Bridge routes are available for the selected token +- The relayer supports the selected token on the origin chain -8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details +### Circle CCTP {: #circle-cctp} -## Explore the Launchpad Dashboard +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. -To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. +This route appears if all of the following conditions are satisfied: -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) +- Both the origin and destination chains support Circle CCTP +- The selected token is native Circle-issued USDC -The dashboard provides a high-level view of your token across all deployed chains, including: +### ETH Bridge {: #eth-bridge} - - Token addresses for each chain - - Supply distribution visualization - - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) +This route appears if all of the following conditions are satisfied: -## Settings +- Both the origin and destination chains support the ETH Bridge +- The selected token is native ETH, wstETH, or canonical wETH -The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. +### Gas Drop Off {: #gas-drop-off} -### Chain Management +A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. -Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. +This route appears if all of the following conditions are satisfied: -From this section, you can also: +- Both the origin and destination chains support gas drop off +- An automatic route is selected +- The relayer accepts the selected token to swap into the gas token +--- END CONTENT --- - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Architecture +description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +categories: NTT, Transfer +--- -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) +## Introduction -### Role Management +The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. -This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers +## System Components -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) +The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. -### Security Threshold +### Managers -Determine and update how transceivers interact with the token. [Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. -A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. +Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers +A manager is responsible for: -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) +- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer +- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers + - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted + - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded -### Peer Chains Limits + Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit -Define the transfer restrictions for each connected network. You can adjust: +- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed +- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains +### Transceivers -Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. +_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) ---- END CONTENT --- +While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- +Transceivers are entrusted with several responsibilities: -# Install the Native Token Transfers CLI +- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing +- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer +- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. +How it works: -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +1. The transceiver receives instructions from the manager to send messages across chains +2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred +3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain -
+![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) -## Install NTT CLI +!!! note + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: +#### Custom Transceivers -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} +The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. -Follow these steps to install the NTT CLI: +NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -1. Run the installation command in your terminal: +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` +The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. -2. Verify the NTT CLI is installed: +For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. - ```bash - ntt --version - ``` +## Lifecycle of a Message -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI +The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. -## Update NTT CLI +### Transfer -To update an existing NTT CLI installation, run the following command in your terminal: +The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. -```bash -ntt update -``` +In both cases: -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. +- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain +- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain -For local development, you can update your CLI version from a specific branch or install from a local path. +Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. -To install from a specific branch, run: +### Rate Limit -```bash -ntt update --branch foo -``` +Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` +- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error +- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. +Both chains emit events or logs when transfers are rate-limited or queued. -## Where to Go Next +### Send -
+After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. +- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message +- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** +In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. - --- +### Receive - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) +- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers +- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** +In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. - --- +### Mint or Unlock - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) +- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred +- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced -
+In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/security/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +title: Native Token Transfers Security +description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. categories: NTT, Transfer --- -# Native Token Transfers Post Deployment +# Security -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): +## Global Accountant -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment +The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. -## Manual Relaying for Solana Transfers +This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. +[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. +## Governance and Upgradeability -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. +Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. -## Where to Go Next +The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: -
+- Adding or removing a transceiver address from the registry +- Setting the token contract address on a bridging contract +- Setting the Wormhole Core Contract address on a bridging contract +- Setting the registered bridging contract address on the token contract -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** +This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Access Control +description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +categories: NTT, Transfer +--- - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. +## Owner and Pauser Roles - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) +Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** +NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. - --- +- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused +- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. +You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) +```json +{ + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": true, // set to true to pause the contract + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + //... + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } +} +``` -
+!!! note + While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. + +The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. + +Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ --- BEGIN CONTENT --- --- -title: Troubleshooting NTT Deployment -description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +title: Native Token Transfers Rate Limiting +description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. categories: NTT, Transfer --- -# Troubleshooting NTT Deployment +## Introduction + +The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. + +If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. + +You can configure the following limits on every chain where NTT is deployed directly using the manager: + +- **Sending limit** - a single outbound limit for sending tokens from the chain +- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum + +Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. -If you encounter issues during the NTT deployment process, check the following common points: +## Update Rate Limits -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain -- **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} -- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file +To configure or update the sending and receiving rate limits, follow these steps: - ???- interface "Dockerfile" +1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts - ```Dockerfile - FROM ubuntu:20.04 - # Set environment variables to prevent interactive prompts during installation - ENV DEBIAN_FRONTEND=noninteractive +2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed - # Update and install necessary dependencies - RUN apt-get update && apt-get install -y \ - curl \ - wget \ - git \ - build-essential \ - libssl-dev \ - libudev-dev \ - pkg-config \ - python3 \ - python3-pip \ - software-properties-common \ - ca-certificates \ - unzip \ - clang \ - cmake \ - protobuf-compiler \ - && apt-get clean && rm -rf /var/lib/apt/lists/* + ```json + "limits": { + "outbound": "1000.000000000000000000", + "inbound": { + "Ethereum": "100.000000000000000000", + "Arbitrum": "50.000000000000000000" + } + } + ``` - # Install Rust - RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - ENV PATH="/root/.cargo/bin:$PATH" + - **`outbound`** - sets the maximum tokens allowed to leave the chain + - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains - # Install Solana CLI ({{ntt.solana_cli_version}}) - RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" - ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" +3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain - # Install Anchor using avm - RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ - && avm install 0.29.0 \ - && avm use 0.29.0 - ENV PATH="/root/.avm/bin:$PATH" + ```bash + ntt push + ``` +4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status - ENV NVM_DIR=/root/.nvm - RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install 22 \ - && nvm use 22 \ - && nvm alias default 22 - ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" + ```bash + ntt status + ``` - # Install Bun - RUN curl -fsSL https://bun.sh/install | bash - ENV PATH="/root/.bun/bin:$PATH" +???- note "`deployment.json` example" + ```json + { + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": false, + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", + "transceivers": { + "threshold": 1, + "wormhole": { + "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + }, + "limits": { + "outbound": "184467440737.095516150000000000", + "inbound": { + "ArbitrumSepolia": "500.000000000000000000" + } + }, + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } + } + ``` - # Install Foundry - RUN curl -L https://foundry.paradigm.xyz | bash - ENV PATH="/root/.foundry/bin:${PATH}" - RUN /bin/bash -c "source /root/.bashrc && foundryup" +## Queuing Mechanism - # Install Wormhole NTT CLI - RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash +When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: - # Add a default working directory - WORKDIR /app +- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer +- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain - # Expose port for development if needed - EXPOSE 8899 +Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. - # Entry point for the container - CMD ["bash"] - ``` +## Cancel Flows - ???- interface "docker-compose.yml" - ```yml - services: - portal-ntt: - build: - context: . - dockerfile: Dockerfile - platform: linux/amd64 - volumes: - - ./src:/app - working_dir: /app - tty: true - ``` +If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ @@ -6262,7 +5714,7 @@ categories: NTT, Transfer Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. -Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/learn/transfers/native-token-transfers/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. +Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. ## What causes the "No protocols registered for Evm" error in Wormhole SDK? @@ -6388,3350 +5840,3439 @@ Yes. NTT tokens can be used with chains that do not support NTT by leveraging th This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/managers-transceivers/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +title: Native Token Transfers EVM Deployment +description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. categories: NTT, Transfer --- -# Managers and Transceivers +# Native Token Transfers (NTT) EVM Development -## Managers +## Deploy Your Token and Ensure Compatibility -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: +If you still need to do so, deploy the token contract to the destination or spoke chains. -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain +### Requirements for Token Deployment - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` +Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. -- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer +#### Burn-and-Mint Mode - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` +Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: -- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected +- `burn(uint256 amount)` +- `mint(address account, uint256 amount)` + +These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. +??? code "View the complete `INttToken` Interface`" ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner + // SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +interface INttToken { + /// @notice Error when the caller is not the minter. + /// @dev Selector 0x5fb5729e. + /// @param caller The caller of the function. + error CallerNotMinter(address caller); + + /// @notice Error when the minter is the zero address. + /// @dev Selector 0x04a208c7. + error InvalidMinterZeroAddress(); + + /// @notice Error when insufficient balance to burn the amount. + /// @dev Selector 0xcf479181. + /// @param balance The balance of the account. + /// @param amount The amount to burn. + error InsufficientBalance(uint256 balance, uint256 amount); + + /// @notice The minter has been changed. + /// @dev Topic0 + /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. + /// @param newMinter The new minter. + event NewMinter(address previousMinter, address newMinter); + + // NOTE: the `mint` method is not present in the standard ERC20 interface. + function mint(address account, uint256 amount) external; + + // NOTE: the `setMinter` method is not present in the standard ERC20 interface. + function setMinter(address newMinter) external; + + // NOTE: NttTokens in `burn` mode require the `burn` method to be present. + // This method is not present in the standard ERC20 interface, but is + // found in the `ERC20Burnable` interface. + function burn(uint256 amount) external; +} ``` -## Transceivers +Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. -_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: +#### Hub-and-Spoke Mode + +A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. + + - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains + - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers + +!!! note + The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. + +For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. + +This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. + +For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. + +### Key Differences Between Modes + + - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently + - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency + +## Deploy NTT + +Create a new NTT project: + +```bash +ntt new my-ntt-deployment +cd my-ntt-deployment +``` + +Initialize a new `deployment.json` file specifying the network: -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system +=== "Testnet" - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager + ```bash + ntt init Testnet ``` -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees +=== "Mainnet" - ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) + ```bash + ntt init Mainnet ``` -## Lifecycle of a Message - -### EVM +Ensure you have set up your environment correctly: -#### Transfer +```bash +export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY +``` -A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. +Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: -**Events** +```bash +# Set scanner API Keys as environment variables +export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY +export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); +# Add each chain +# The contracts will be automatically verified using the scanner API keys above +ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS ``` -#### Rate Limit - -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. +While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. -If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. +The `ntt add-chain` command takes the following parameters: -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. +- Name of each chain +- Version of NTT to deploy (use `--latest` for the latest contract versions) +- Mode (either `burning` or `locking`) +- Your token contract address -If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. +The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. +## Configure NTT -**Events** +The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: -```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); -``` +- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain +- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` + For Solana, the limits are set with 9 decimal places: + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + } + ``` -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` + For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: + ```json + "inbound": { + "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia + } + ``` -#### Send + This initial configuration ensures that the rate limits are correctly represented for each chain's token precision + +- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). +After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. +## Set Token Minter to NTT Manager -**Events** +The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. -```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); -``` +!!! note + The required NTT Manager address can be found in the `deployment.json` file. -#### Receive +- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function + ```json + cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + ``` -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. +- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. +By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. +!!!important + To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. +--- END CONTENT --- -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Solana Deployment +description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. +# Deploy Native Token Transfers on Solana -**Events** +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); -``` +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` +By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); -``` +## Prerequisites -#### Mint or Unlock +Before deploying NTT on Solana, ensure you have the following: -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. +- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} +- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** +- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -**Events** +Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` +## Overview of the Deployment Process -### Solana +Deploying NTT with the CLI on Solana follows a structured process: -#### Transfer +1. **Choose your token setup**: -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. + - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section + - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. + ???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. -Depending on the mode and instruction, the following will be produced in the program logs: + 1. **Generate a Solana key pair** - run the following command to create a new wallet: -```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: -#### Rate Limit + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: -If the transfer amount fits within the current capacity: + === "Mainnet" + ```bash + solana config set -um + ``` -- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. + === "Testnet" + ```bash + solana config set -ut + ``` -If the transfer amount doesn't fit within the current capacity: + === "Devnet" + ```bash + solana config set -ud + ``` -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: -#### Send + ```bash + solana airdrop 2 + solana balance + ``` -The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. + ```bash + cargo install spl-token-cli + ``` -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. + 6. **Create a new SPL token** - initialize the token on Solana -The following will be produced in the program logs: + ```bash + spl-token create-token + ``` -```ts -Program log: Instruction: ReleaseOutbound -``` + 7. **Create a token account** - generate an account to hold the token -#### Receive + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. + 8. **Mint tokens** - send 1000 tokens to the created account -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` -The following will be produced in the program logs: + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -```ts -Program log: Instruction: ReceiveMessage -``` +2. **Choose your [deployment model](TODO){target=\_blank}**: -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program -The following will be produced in the program logs: +3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode -```ts -Program log: Instruction: Redeem -``` +Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -#### Mint or Unlock +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. -The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. +## Set Up NTT -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. +To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -Depending on the mode and instruction, the following will be produced in the program logs: +The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock -``` ---- END CONTENT --- +1. **Create a new NTT project** - set up a deployment workspace -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement -description: Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. -categories: Settlement, Transfer ---- + ```bash + ntt new INSERT_PROJECT_NAME + cd INSERT_PROJECT_NAME + ``` -# Wormhole Settlement +2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings -## Get Started + === "Mainnet" -This section provides resources to build with Wormhole Settlement, including integrating the Liquidity Layer into your application and running a Solver for efficient cross-chain asset transfers. + ```bash + ntt init Mainnet + ``` -
+ === "Testnet" -- :octicons-code-16:{ .lg .middle } **Build on the Liquidity Layer** + ```bash + ntt init Testnet + ``` +!!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. - --- +### Set Mint Authority - Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. +If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. - [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) +If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). -- :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** +Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. - --- +Follow these steps to set the mint authority using the NTT CLI: - Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment - [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` -
---- END CONTENT --- +2. **Derive the token authority** - generate the PDA, which will manage token minting -Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement FAQs -description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. -categories: Settlement, Transfer ---- + ```bash + ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR + ``` -# Wormhole Settlement FAQs +3. **Set SPL token mint authority** - delegate minting control to the derived PDA -## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? + ```bash + spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA + ``` -Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. +## Deploy and Configure NTT -## What happens if no solver participates in the auction? +After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: -If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. +1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: -## What guarantees does Wormhole Settlement provide for message execution? + === "Burn-and-Mint" -After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). + ```bash + ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` -If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. ---- END CONTENT --- + === "Hub-and-Spoke" -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- + ```bash + ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` -# Build on the Wormhole Liquidity Layer + !!! tip + The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. -## Introduction +2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. + ```bash + ntt status + ``` -## EVM Functions + If needed, sync your local configuration with the on-chain state: -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. + ```bash + ntt pull + ``` -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. -### Fast Market Order + Open your `deployment.json` file and adjust the values based on your use case: -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + }, + "outbound": { + "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia + } + ``` -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` +4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees -??? interface "Parameters `placeFastMarketOrder()`" + ```bash + ntt push --payer INSERT_YOUR_KEYPAIR_JSON + ``` - `amountIn` ++"uint128"++ +### Troubleshoot Deployment Issues + +If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. - The amount to transfer. +## Where to Go Next - --- +
- `targetChain` ++"uint16"++ +- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** - Target chain ID. + --- - --- + After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - `redeemer` ++"bytes32"++ + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - Redeemer contract address. +- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** --- - `redeemerMessage` ++"bytes"++ + Follow the NTT Post Deployment Guide for integration examples and testing instructions. - An arbitrary payload for the redeemer. + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + +- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** --- - `maxFee` ++"uint128"++ + Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. - The maximum fee the user wants to pay to execute a fast transfer. + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} - --- +
+--- END CONTENT --- - `deadline` ++"uint32"++ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +--- BEGIN CONTENT --- +--- +title: Deploy Native Token Transfers with Launchpad +description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +categories: NTT, Transfer +--- - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. +# Deploy Native Token Transfers with Launchpad -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. +## Introduction -### Market Order +The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. +Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` +The Launchpad automates deployment, reducing complexity and saving time. -??? interface "Parameters `placeMarketOrder()`" +This guide covers: - `amountIn` ++"uint128"++ + - Launching a new cross-chain token + - Expanding an existing token for NTT + - Managing tokens via the dashboard and settings - The amount to transfer. +## Prerequisites - --- + - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) + - Minimum ETH (or equivalent) for gas fees per deployment - `targetChain` ++"uint16"++ +## Supported Blockchains - Target chain ID. +The NTT Launchpad currently supports deployments on the following mainnet chains: - --- + - Ethereum + - Arbitrum One + - Base + - Berachain + - Blast + - BNB Smart Chain + - Ink + - Optimism Mainnet + - Polygon - `redeemer` ++"bytes32"++ +## Choose Your Path + +Once ready, choose an option to proceed: - Redeemer contract address. + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains + - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract - --- +## Launch a Cross-Chain Token - `redeemerMessage` ++"bytes"++ +Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: - An arbitrary payload for the redeemer. +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Launch a Cross-Chain Token** -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) -# Run a Wormhole Settlement Solver +3. Set the token details: + 1. Select the **home network** from the dropdown menu + 2. Enter the **name** for the token + 3. Enter the **symbol** of the token + 4. Provide the **initial supply** + 5. To the token details, click **Next** -## Introduction + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. +4. Select the deployment chains: + 1. The home network where your token will be deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** -A Solver is an off-chain agent responsible for: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) -## Background +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step -These instructions work together to carry out the auction as follows: +8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent +## Expand Your Existing Token -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. +Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** -## Testnet Example Solver + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. +2. Select **Expand Your Existing Token** -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) -### Prerequisites +3. Enter the token details: + 1. Choose the home network where your token is already deployed (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** -In order to build and install dependencies locally in this repo, you will need: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} +4. Select the chains to deploy your token to: + 1. The home network where your token is already deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 1. Click **Next** -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) -```sh -make dependencies -``` +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction -### Set up Config + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - } - ] -} -``` + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step -### Listen to Activity +8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. +## Explore the Launchpad Dashboard -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` +To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -You should see output resembling: +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) -
- Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
+The dashboard provides a high-level view of your token across all deployed chains, including: -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: + - Token addresses for each chain + - Supply distribution visualization + - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -=== "Linux" +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` +## Settings -=== "MacOS" +The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` +### Chain Management -### Running the Example Solver +Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. -Using the same config for your publisher, run the example solver with the command below. +From this section, you can also: -```sh -CONFIG=path/to/config.json make run-solver -``` + - **Pause the token** – temporarily turn off transfers on the selected chain + - **Deploy to a new chain** – expand your token by deploying it to an additional chain -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) -This process reads the following environment variables: +### Role Management -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. + - **Manager’s Owner** – the owner through the `NTTOwner` proxy + - **Pauser** – the address authorized to pause transfers -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. +### Security Threshold -An address lookup table is required to execute some transactions. Use the command below to create one. +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. -```sh -CONFIG=path/to/config.json make create-lut -``` +A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. + - **Registered Transceivers** – displays the number of registered transceivers and their addresses + - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -The example solver has the following toggles depending on which orders you want to fulfill: +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` +### Peer Chains Limits -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. +Define the transfer restrictions for each connected network. You can adjust: -This example solver does NOT do the following: + - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain + - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want +Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. + +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/token-bridge/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- -title: Get Started with Token Bridge -description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -categories: Token-Bridge, Transfer +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer --- -# Token Bridge - -## Introduction - -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. - -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +# NTT CLI Commands -## Prerequisites +## Introduction -To interact with the Wormhole Token Bridge, you'll need the following: +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. -## How to Interact with Token Bridge Contracts +## Table of Commands -The primary functions of the Token Bridge contracts revolve around: +The following table lists the available NTT CLI commands, descriptions, and examples. -- **Attesting a token** - registering a new token for cross-chain transfers -- **Transferring tokens** - locking and minting tokens across chains -- **Transferring tokens with a payload** - including additional data with transfers +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. -### Attest a token +### General Commands -Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. +| Command | Description | Examples | +|-----------------------------------------|-------------------------------------------------------|--------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| +| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | -The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. +### Configuration Commands -```solidity -function attestToken( - address tokenAddress, - uint32 nonce -) external payable returns (uint64 sequence); -``` +| Command | Description | Examples | +|---------------------------------------------|----------------------------------------|-------------------------------------| +| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| +| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| -??? interface "Parameters" +### Solana Commands - `tokenAddress` ++"address"++ - - The contract address of the token to be attested. +| Command | Description | Examples | +|-----------------------------------------------|---------------------------------------------------------|------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| +| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| +| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| - --- +## Where to Go Next - `nonce` ++"uint32"++ +
- An arbitrary value provided by the caller to ensure uniqueness. -??? interface "Returns" +- :octicons-gear-16:{ .lg .middle } **Configure NTT** - `sequence` ++"uint64"++ - - A unique identifier for the attestation transaction. + --- -When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) -### Transfer Tokens +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. + --- -Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -```solidity -function transferTokens( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint256 arbiterFee, - uint32 nonce -) external payable returns (uint64 sequence); -``` + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) -??? interface "Parameters" +
+--- END CONTENT --- - `token` ++"address"++ - - The address of the token being transferred. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ +--- BEGIN CONTENT --- +--- +title: Troubleshooting NTT Deployment +description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +categories: NTT, Transfer +--- - --- +# Troubleshooting NTT Deployment - `amount` ++"uint256"++ - The amount of tokens to be transferred. +If you encounter issues during the NTT deployment process, check the following common points: - --- +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} + - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** + - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain +- **Mint authority transfer** + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} +- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. + ???- interface "Dockerfile" - --- + ```Dockerfile + FROM ubuntu:20.04 + # Set environment variables to prevent interactive prompts during installation + ENV DEBIAN_FRONTEND=noninteractive - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. + # Update and install necessary dependencies + RUN apt-get update && apt-get install -y \ + curl \ + wget \ + git \ + build-essential \ + libssl-dev \ + libudev-dev \ + pkg-config \ + python3 \ + python3-pip \ + software-properties-common \ + ca-certificates \ + unzip \ + clang \ + cmake \ + protobuf-compiler \ + && apt-get clean && rm -rf /var/lib/apt/lists/* - --- + # Install Rust + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + ENV PATH="/root/.cargo/bin:$PATH" - `arbiterFee` ++"uint256"++ - Optional fee to be paid to an arbiter for relaying the transfer. + # Install Solana CLI ({{ntt.solana_cli_version}}) + RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" + ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" - --- + # Install Anchor using avm + RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ + && avm install 0.29.0 \ + && avm use 0.29.0 + ENV PATH="/root/.avm/bin:$PATH" - `nonce` ++"uint32"++ - A unique identifier for the transaction. -??? interface "Returns" + ENV NVM_DIR=/root/.nvm + RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ + && . "$NVM_DIR/nvm.sh" \ + && nvm install 22 \ + && nvm use 22 \ + && nvm alias default 22 + ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. + # Install Bun + RUN curl -fsSL https://bun.sh/install | bash + ENV PATH="/root/.bun/bin:$PATH" -Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. + # Install Foundry + RUN curl -L https://foundry.paradigm.xyz | bash + ENV PATH="/root/.foundry/bin:${PATH}" + RUN /bin/bash -c "source /root/.bashrc && foundryup" -```solidity -function completeTransfer(bytes memory encodedVm) external; -``` + # Install Wormhole NTT CLI + RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash -??? interface "Parameters" + # Add a default working directory + WORKDIR /app - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. + # Expose port for development if needed + EXPOSE 8899 -!!!note - - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain + # Entry point for the container + CMD ["bash"] + ``` -### Transfer tokens with payload + ???- interface "docker-compose.yml" + ```yml + services: + portal-ntt: + build: + context: . + dockerfile: Dockerfile + platform: linux/amd64 + volumes: + - ./src:/app + working_dir: /app + tty: true + ``` +--- END CONTENT --- -While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. +# Products -```solidity -function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload -) external payable returns (uint64 sequence); -``` +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -??? interface "Parameters" +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. - `token` ++"address"++ - - The address of the token being transferred. +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. - --- +## Transfer Products - `amount` ++"uint256"++ - The amount of tokens to be transferred. +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - --- +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. +
- --- +::spantable:: - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | - --- +::end-spantable:: - `nonce` ++"uint32"++ - A unique identifier for the transaction. +
- --- +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. - `payload` ++"bytes memory"++ - Arbitrary data payload attached to the transaction. +## Real-time Data -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. +## Multichain Governance -Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -```solidity -function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); -``` +Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: Settlement Protocol Architecture +description: Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. +categories: Settlement, Transfer +--- -??? interface "Parameters" +# Settlement Protocol Architecture - `encodedVm` ++"bytes memory"++ +## Introduction - The signed VAA containing the transfer details. +This page describes the high-level mechanics of the underlying native swap protocols in the Wormhole SDK. While built on Wormhole messaging, each protocol uses a novel architecture with unique price discovery, scalability, and latency tradeoffs. These designs enable redundancy to handle highly asymmetric flows and sharp volume changes. These sections will cover the following: -??? interface "Returns" +- **Wormhole Liquidity Layer** - a cross-chain transfer protocol that utilizes Solana as the central orchestration layer for cross-chain intents, allowing solvers to deploy liquidity from a single Solana-based hub rather than distributing it across each supported chain +- **Mayan Swift** - a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent +- **Mayan MCTP** - a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains - `bytes memory` +## Wormhole Liquidity Layer - The extracted payload data. +Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster-than-finality transfers across the Wormhole ecosystem through a novel, Solana-based hub-and-spoke architecture. The hub-and-spoke model leverages interoperable token standards like Circle's CCTP (and Wormhole's NTT), allowing the solver to natively mint and burn assets between chains for intent fulfillment. This architecture allows solvers to facilitate cross-chain transfers by fronting assets on the destination chain and assuming the finality risk of the originating source chain transaction. -## Source Code References +Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. -For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) -- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} -- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} +The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. -## Portal Bridge +### Solvers and Liquidity Fragmentation -A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +Traditional intent-based protocols require solvers to distribute their capital across each supported chain in the network. This liquidity fragmentation leads to capital inefficiency and requires complex rebalancing to manage asymmetric flows between chains. As the number of chains increases, solvers face scalability challenges, which can result in market concentration, reducing competition and potentially impacting price discovery in intent execution. -## FAQs +Using a hub-and-spoke model, the Wormhole Liquidity Layer solves these challenges by consolidating solver liquidity on a single chain, Solana. This model eliminates the need for complex cross-chain rebalancing and simplifies solvers' infrastructure requirements. Solvers only need to consider the finality risk of the originating source chain transaction and the payload size when bidding on transfers. By concentrating liquidity on Solana, the protocol can handle large transfer volumes with a smaller capital base, enhancing capital efficiency and lowering barriers to entry for solvers. This approach promotes competition, improves overall market efficiency, and ultimately benefits users with better prices while still preserving the speed of transactions. -### Can ownership of wrapped tokens be transferred from the Token Bridge? +### Enable Unified Liquidity -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +The novel hub-and-spoke liquidity architecture relies on interoperable token standards that enable cross-chain token fungibility, such as Circle's Cross-Chain Transfer Protocol (CCTP) and Wormhole's Native Token Transfers (NTT). These protocols allow assets to move seamlessly between chains, making unified liquidity possible. On the liquidity hub (Solana), solvers concentrate their liquidity in NTT or CCTP-supported assets, such as USDC. These assets act as the shuttle between chains but may not necessarily be the user's original or final asset. - - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge +After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. -The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. -Relevant contracts: +### Protocol Flow: How It Works - - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} - - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} +1. **Initiation** - users or protocols initiate a transfer via an interface or directly on-chain. They choose between a standard transfer (waiting for finality on the sending chain) or a fast transfer (triggering the auction process). For fast transfers, users or the protocol specify a maximum fee and an auction start deadline -### How do I update the metadata of a wrapped token? + !!! Note + If an auction doesn't start within the set deadline, a standard transfer will proceed directly from the source to the destination chain. -Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. +2. **Auction** - solvers monitor the Wormhole network for these fast transfer requests and initiate an auction on Solana by offering to fulfill the transfer at or below the user's maximum fee. To start the auction, the solver must transfer the requested funds plus a small security deposit to the Matching Engine contract +3. **Competition** - once initiated, other solvers can participate by submitting lower bids in a simple English auction, aiming to provide users with the best rate. If a new solver submits a better offer, the previous solver's funds and security deposit are returned, with the latest offer taking precedence atomically. This competition ensures that users receive the best possible transfer rate +4. **Fulfillment** - after the auction concludes, the winning solver must complete the transfer within a predefined grace period to earn their fee and reclaim their security deposit. Failure to do so may result in the security deposit being slashed, with the slashed amount compensating the user for delays. This mechanism incentivizes prompt execution. Upon successful completion, the Fast Transfer hub sends the USDC to the user's destination wallet, and the solver receives their security deposit and transfer fee +5. **Settlement** - once the source chain transaction reaches finality, the winning solver can use the finalized Wormhole message to settle the auction with the matching engine and rebalance. This allows the solver to retrieve the original transfer amount into their wallet -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +## Mayan Swift -You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. +Mayan Swift is a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent. -### How can I update my wrapped token image on Solscan? +### On-Chain Competitive Price Discovery Mechanism -Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. +Traditional intent-based protocols essentially function as cross-chain limit orders. If the order is profitable, solvers will compete to fulfill it, leading to MEV-like competition focused on speed. While functional, this methodology presents two clear inefficiencies and drawbacks. -To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. ---- END CONTENT --- +First, they lack a competitive price discovery mechanism as limit order prices are typically determined through centralized off-chain systems. Second, in this MEV-like market structure, only a single solver can win, while the others lose out on transaction fees. This dynamic of deadweight loss results in solvers prioritizing high-margin orders, ultimately resulting in elevated fees for end-users without commensurate benefits. -Doc-Content: https://wormhole.com/docs/tutorials/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect Tutorials -description: Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -categories: Connect, Transfer ---- +Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -# Connect +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) -Wormhole Connect makes it simple to link your application to multiple blockchain ecosystems. These tutorials will teach you how to integrate Connect into your projects, streamline cross-chain interactions, simplify user onboarding, and deliver a smoother overall experience. +### Protocol Flow: How It Works -## Tutorials +1. **Initiation** - the user creates an order by signing a transaction that locks one of the primary assets (USDC or ETH) into the Mayan smart contract, specifying the desired outcome. -
+ !!!note + If the input asset is not a primary asset, it is converted into a primary asset within the same transaction before the order is submitted. -- :octicons-repo-16:{ .lg .middle } **Integrate Connect into a React DApp** + Each order includes properties such as destination chain, destination wallet address, output token address, minimum output amount, gas drop amount, deadline, and 32 bytes of random hex to prevent collisions. A Keccak-256 hash is then calculated to identify the order - --- +2. **Auction** - solvers observe on-chain data or subscribe to the Mayan explorer web socket (solvers using the Mayan explorer verify the order's integrity by checking the data against the on-chain hash). Once the new order is verified, an on-chain auction on Solana is initiated by passing the order ID and the bid amount, which cannot be lower than the minimum amount. Other solvers can increase the bid by submitting a higher amount before the auction ends +3. **Fulfillment** - the auction ends three seconds after the initial bid. Once the auction ends, the winning solver can execute an instruction that passes their wallet address on the destination chain. This triggers a Wormhole message containing the order ID and the winner's wallet address. Wormhole Guardians then sign this message, allowing the winning solver to fulfill the order on the destination chain by submitting proof of their win and the promised amount to the Mayan contract before the deadline. The Mayan contract deducts a protocol fee (currently 3 basis points) and a referral fee (if applicable), transferring the remaining amount to the user's destination wallet. It also triggers a Wormhole message as proof of fulfillment +4. **Settlement** - after the Wormhole Guardians sign the fulfillment message, the winning solver can submit this message on the source chain to unlock the user's funds and transfer them to their own wallet. Upon fulfillment, the solver has the option to delay triggering a Wormhole message immediately. Instead, they can batch the proofs and, once the batch reaches a certain threshold, issue a batched proof to unlock all orders simultaneously, saving on gas fees - Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. +## Mayan MCTP - [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) +Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -
+![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) -## Additional Resources +### Protocol Flow: How It Works -
+1. **Initiation** - the user creates an order by signing a transaction that locks one USDC into the Mayan smart contract, specifying the desired outcome. -- :octicons-tools-16:{ .lg .middle } **Connect** + !!!note + If the input asset is not USDC, it is converted into a primary asset within the same transaction before the order is submitted. + + The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash - --- +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} +3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules - Get deeper insights into setting up and customizing Wormhole Connect. Explore advanced guides, best practices, and configuration tips to streamline your cross-chain integrations. +The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. - [:custom-arrow: Learn more](/docs/build/transfers/connect/) +## Where to Go Next -
+- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide +- To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- -title: Integrate Connect into a React DApp Tutorial -description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -categories: Connect, Transfer +title: Wormhole Settlement FAQs +description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. +categories: Settlement, Transfer --- -# Integrate Connect into a React DApp +# Wormhole Settlement FAQs -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} +## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? -## Introduction +Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. -In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. +## What happens if no solver participates in the auction? -While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. +If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. -## Prerequisites +## What guarantees does Wormhole Settlement provide for message execution? -To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. -Before starting this tutorial, ensure you have the following: +After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use -- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} -- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees +If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. +--- END CONTENT --- -## Set Up Connect for Sui Transfers +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Liquidity Layer +description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. +categories: Settlement, Transfer +--- -### Create a React Project +# Build on the Wormhole Liquidity Layer -Start by setting up your React app: +## Introduction -1. Open your terminal and run the following command to create a new React app: +The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. - ```bash - npx create-react-app connect-tutorial - ``` +## EVM Functions -2. Navigate into the project directory: +The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - ```bash - cd connect-tutorial - ``` +See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. -### Install Wormhole Connect +### Fast Market Order -Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: +The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` -```bash -npm install @wormhole-foundation/wormhole-connect +```solidity title="`placeFastMarketOrder` Interface" +function placeFastMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, + uint128 maxFee, + uint32 deadline +) external payable returns (uint64 sequence, uint64 fastSequence); ``` -### Integrate Connect into the Application +??? interface "Parameters `placeFastMarketOrder()`" -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: + `amountIn` ++"uint128"++ -=== "JavaScript" + The amount to transfer. - ```js - import logo from './logo.svg'; - import './App.css'; - import WormholeConnect from '@wormhole-foundation/wormhole-connect'; + --- - const config = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], - }; + `targetChain` ++"uint16"++ - function App() { - return ; - } + Target chain ID. - export default App; - ``` + --- -=== "TypeScript" + `redeemer` ++"bytes32"++ - ```ts - import './App.css'; - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - } from '@wormhole-foundation/wormhole-connect'; + Redeemer contract address. - function App() { - const config: WormholeConnectConfig = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], + --- - ui: { - title: 'SUI Connect TS Demo', - }, - }; + `redeemerMessage` ++"bytes"++ - const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - }; + An arbitrary payload for the redeemer. - return ; - } + --- - export default App; - ``` + `maxFee` ++"uint128"++ -- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment -- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche + The maximum fee the user wants to pay to execute a fast transfer. -### Customize Wormhole Connect + --- -To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/build/transfers/connect/configuration/#introduction){target=\_blank}. + `deadline` ++"uint32"++ -### Run the Application + The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. -Make sure you’re in the root directory of your React app, and run the following command to start the application: +The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. -```bash -npm start -``` +### Market Order -Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. +The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. -## Transfer Tokens from Sui to Fuji +```solidity title="`placeMarketOrder` Interface" +function placeMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, +) external payable returns (uint64 sequence, uint64 protocolSequence); +``` -Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. +??? interface "Parameters `placeMarketOrder()`" -To transfer tokens from Sui to Fuji in the Wormhole Connect interface: + `amountIn` ++"uint128"++ -1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer -2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network -3. Enter the amount of SUI tokens you wish to transfer + The amount to transfer. - ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) + --- -4. Choose to view other routes - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) + `targetChain` ++"uint16"++ -5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) + Target chain ID. - !!! note - It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. + --- - ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) + `redeemer` ++"bytes32"++ -6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain + Redeemer contract address. - ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) + --- -7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet + `redeemerMessage` ++"bytes"++ - ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) + An arbitrary payload for the redeemer. -Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. +--- END CONTENT --- -## Claim Tokens on Fuji +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Solver +description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +categories: Settlement, Transfer +--- -After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. +# Run a Wormhole Settlement Solver -![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) +## Introduction -Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. +This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. -![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) +A Solver is an off-chain agent responsible for: -## Resources +- Listening to cross-chain transfer requests sent over Wormhole +- Bidding in auctions (on Solana) to fulfill each request +- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain +- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. -## Conclusion +## Background -In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. +The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: -By following these steps, you've learned how to: +1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details +2. `bid` - allows a solver to place or update a bid on the active auction +3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. +4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners -- Set up a React project tailored for cross-chain transfers -- Install and configure Wormhole Connect to support multiple blockchains -- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers -- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks +These instructions work together to carry out the auction as follows: -With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. ---- END CONTENT --- +- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity +- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver +- The originating solver can repurpose the returned funds and use them to improve their bid +- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent -## Basics Concepts [shared: true] +When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. +If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. ---- +## Testnet Example Solver -## List of shared concept pages: +You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. +!!!warning + This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. -## Full content for shared concepts: +### Prerequisites -Doc-Content: https://wormhole.com/docs/learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- +In order to build and install dependencies locally in this repo, you will need: -# Glossary +- node v20.18.1 +- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: -## Chain ID +```sh +make dependencies +``` -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +### Set up Config -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. -## Consistency Level +```json title="config.json" +{ + "environment": "Testnet", + "zmqChannels": { + "fastVaa": "tcp://localhost:6001", + "finalizedVaa": "tcp://localhost:6002" + }, + "publisher": { + "log": { + "level": "info" + }, + "vaaSpy": { + "host": "localhost:7073", + "enableObservationCleanup": true, + "observationSeenThresholdMs": 1500000, + "observationCleanupIntervalMs": 500, + "observationsToRemovePerInterval": 5, + "delayedThresholdMs": 60000 + } + }, + "solver": { + "log": { + "level": "info", + "filename": "logs/solver.log" + }, + "connection": { + "rpc": "", + "maxTransactionsPerSecond": 5, + "commitment": "processed", + "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", + "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", + "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "knownAtaOwners": [ + "Payer11111111111111111111111111111111111111", + "Payer11111111111111111111111111111111111112", + "Payer11111111111111111111111111111111111113" + ] + } + }, + "routerEndpoints": [ + { + "chain": "Sepolia", + "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Avalanche", + "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "OptimismSepolia", + "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "ArbitrumSepolia", + "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "BaseSepolia", + "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Polygon", + "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + } + ] +} +``` -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. -## Delivery Provider +### Listen to Activity -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. -## Emitter +```sh +NETWORK=testnet CONFIG=path/to/config.json make run-publisher +``` -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +You should see output resembling: -## Finality +
+ Start logging with info level. + 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet + 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 + 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 + 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 +
-The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: -## Guardian +=== "Linux" -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + ```sh + sudo sysctl -w net.core.rmem_max=2097152 + sudo sysctl -w net.core.rmem_default=2097152 + ``` -## Guardian Network +=== "MacOS" -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + ```sh + sudo sysctl -w net.inet.udp.recvspace=2097152 + ``` -## Guardian Set +### Running the Example Solver -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +Using the same config for your publisher, run the example solver with the command below. -## Heartbeat +```sh +CONFIG=path/to/config.json make run-solver +``` -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +This process reads the following environment variables: -## Observation +```sh +SOLANA_PRIVATE_KEY_1= +SOLANA_PRIVATE_KEY_2= +SOLANA_PRIVATE_KEY_3= +SOLANA_PRIVATE_KEY_4= +SOLANA_PRIVATE_KEY_5= +``` -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. -## Relayer +The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. -A relayer is any process that delivers VAAs to a destination. +Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. -## Sequence +An address lookup table is required to execute some transactions. Use the command below to create one. -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +```sh +CONFIG=path/to/config.json make create-lut +``` -## Spy +`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The example solver has the following toggles depending on which orders you want to fulfill: -## VAA +- `enableCctpOrderPipeline()` +- `enableLocalOrderPipeline()` +- `enablePlaceInitialOffer()` +- `enableImproveOffer()` -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. -## Validator +This example solver does NOT do the following: -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called +- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it +- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ --- BEGIN CONTENT --- --- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics +title: Token Bridge FAQs +description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +categories: Token-Bridge, Transfer --- -# Infrastructure Components +## FAQs -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +### Can ownership of wrapped tokens be transferred from the Token Bridge? -## Get Started +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. -Start here for an overview of Wormhole architecture components and security mechanisms: + - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself + - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge -
+The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. -- :octicons-book-16:{ .lg .middle } **Architecture Overview** +Relevant contracts: - --- + - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} + - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} + - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +### How do I update the metadata of a wrapped token? - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -- :octicons-book-16:{ .lg .middle } **Security** +### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? - --- +You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. - Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +### How can I update my wrapped token image on Solscan? - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. -
+To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. +--- END CONTENT --- -## Explore Components +## Basics Concepts [shared: true] -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +--- -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +## List of shared concept pages: -## Next Steps -
+## Full content for shared concepts: -- :octicons-book-16:{ .lg .middle } **Messaging Components** +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ +--- BEGIN CONTENT --- +--- +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +categories: Basics +--- - --- +# Wormhole Use Cases - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +
+
- [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +## Cross-Chain Swaps and Liquidity Aggregation -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +Enable seamless swaps between chains with real-time liquidity routing. - --- +
+
- Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +🛠 **Wormhole products used:** - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -
---- END CONTENT --- +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +
+
-# Architecture -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +## Borrowing and Lending Across Chains -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +Let users borrow assets on one chain using collateral from another. -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +
+
-1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +🛠 **Wormhole products used:** - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## On-Chain Components +
+
-- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +## Real-Time Price Feeds and Trading Strategies -## Next Steps +Fetch price feeds across multiple chains for DeFi applications. -
+
+
-- :octicons-book-16:{ .lg .middle } **Core Contracts** +🛠 **Wormhole products used:** - --- +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +
+
-- :octicons-tools-16:{ .lg .middle } **Core Messaging** - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +## Asset Movement Between Bitcoin and Other Chains - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +Enable direct BTC transfers without wrapped assets.
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- +🛠 **Wormhole products used:** -# Core Contracts +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -## Introduction +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +
+
-This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +
+
-## Key Functions +## Decentralized Social Platforms -Key functions of the Wormhole Core Contract include the following: +Enable seamless communication and asset transfer across decentralized social networks. -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +
+
-## How the Core Contract Works +🛠 **Wormhole products used:** -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards -The following describes the role of the Wormhole Core Contract in message transfers: +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +
+
-For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -### Message Submission +
+
-You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +## Memecoin Launchpads -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + +
+
+ +🛠 **Wormhole products used:** + +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -### Message Reception +
+
-When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -## Multicast +
+
-Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +## Cross-Chain Perpetuals -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +
+
-Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +🛠 **Wormhole products used:** -## Next Steps +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences -
+🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** +
+
- --- - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +
+
- [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +## Gas Abstraction -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - --- +
+
- This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +🛠 **Wormhole products used:** - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments + +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ ---- BEGIN CONTENT --- ---- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics ---- -## Guardian +
+
-Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +## Bridging Intent Library -Guardians fulfill their role in the messaging protocol as follows: +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state +
+
-Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -The Guardian Network is designed to help Wormhole deliver on five key principles: +
+
-- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -The following sections explore each principle in detail. +
+
-### Decentralization +## Multichain Prediction Markets -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. -Two common approaches to decentralization have notable limitations: +
+
-- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +🛠 **Wormhole products used:** -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming -To answer that, consider these key constraints and design decisions: +
+
-- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +
+
-### Modularity +## Cross-Chain Payment Widgets -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -### Chain Agnosticism +
+
-Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +🛠 **Wormhole products used:** -### Scalability +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +
+
-Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -### Upgradeable +
+
-Wormhole is designed to adapt and evolve in the following ways: +## Oracle Networks -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +
+
-## Next Steps +🛠 **Wormhole products used:** -
+- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -- :octicons-book-16:{ .lg .middle } **Relayers** +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - --- +
+
- Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +
+
-- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +## Cross-Chain Staking - --- +Enable users to stake assets on one chain while earning rewards or securing networks on another. - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +
+
- [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +🛠 **Wormhole products used:** + +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks + +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -# Relayers +# Glossary -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +## Chain ID -There are three primary types of relayers discussed: +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Consistency Level -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -## Fundamentals +## Delivery Provider -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +## Emitter -Key characteristics of VAAs include: +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -- Public emission from the Guardian Network +## Finality -- Authentication through signatures from the Guardian Network +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -- Verifiability by any entity or any Wormhole Core Contract +## Guardian -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -Keep in mind the following security considerations around relayers: +## Guardian Network -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly +## Guardian Set -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Client-Side Relaying +## Heartbeat -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -### Key Features +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs +## Observation -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -### Implementation +## Relayer -Users themselves carry out the three steps of the cross-chain process: +A relayer is any process that delivers VAAs to a destination. -1. Perform an action on chain A +## Sequence -2. Retrieve the resulting VAA from the Guardian Network +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -3. Perform an action on chain B using the VAA +## Spy -### Considerations +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +--- BEGIN CONTENT --- +--- +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +categories: Basics +--- + +# Get Started with Core Contracts + +## Introduction + +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. + +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. + +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. + +## Prerequisites -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +To interact with the Wormhole Core Contract, you'll need the following: -- Users must sign all required transactions with their own wallet +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -- Users must have funds to pay the transaction fees on every chain involved +## How to Interact with Core Contracts -- The user experience may be cumbersome due to the manual steps involved +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -## Custom Relayers +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). +### Sending Messages -### Key Features +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs +=== "EVM" -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience + ??? interface "Parameters" -### Implementation + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. + --- -### Considerations + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." + --- -- Development work and hosting of relayers are required + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + ??? interface "Returns" -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -## Wormhole Relayers + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -### Key Features +// Check fee and send parameters -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -### Implementation +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -The Wormhole relayer integration involves two key steps: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +=== "Solana" -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -### Considerations + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. + ??? interface "Parameters" -- All computations are performed on-chain + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- Potentially less gas-efficient compared to custom relayers + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- Support may not be available for all chains + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -## Next Steps + ??? child "Type `PostMessage<'info>`" -
+ ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -- :octicons-book-16:{ .lg .middle } **Spy** + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - --- + --- - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `batch_id` ++"u32"++ + + An identifier for the message batch. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. - --- + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - --- + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -# Spy +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. +### Receiving Messages -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. +The way a message is received and handled depends on the environment. -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. +=== "EVM" -## Key Features + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Integrator Use Case + ??? interface "Parameters" -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ??? interface "Returns" -## Observable Message Categories + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -A Spy can access the following categories of messages shared over the gossip protocol: + ??? child "Struct `VM`" -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status + ??? interface "Example" - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## Additional Resources + // Perform safety checks here -
+ // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + // Your custom application logic here +} + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +=== "Solana" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + Retrieve the raw message data: - --- + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. + ??? interface "Example" - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +#### Validating the Emitter - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -
+Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Next Steps +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -
+This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - --- +await tx.wait(); +``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +#### Additional Checks - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- :octicons-code-16:{ .lg .middle } **Use Queries** +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - --- +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +## Source Code References - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +# Wormhole Relayer -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +## Introduction -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +## Get Started with the Wormhole Relayer -## VAA Format +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -The basic VAA consists of header and body components described as follows: +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- Where each `signature` is: +### Wormhole Relayer Interfaces - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Interact with the Wormhole Relayer -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -## Consistency and Finality +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +Your initial set up should resemble the following: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Signatures +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +contract Example { + IWormholeRelayer public wormholeRelayer; -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} ``` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Be aware of the following considerations when working with attestations: +### Send a Message -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -### Token Transfer with Message +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +### Receive a Message -### Governance +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -#### Action Structure +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +## Delivery Guarantees -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -#### Actions +## Delivery Statuses -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Lifetime of a Message +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Other Considerations -## Next Steps +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -
+- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -- :octicons-book-16:{ .lg .middle } **Guardians** +## Track the Progress of Messages with the Wormhole CLI - --- +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +=== "Mainnet" - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +=== "Testnet" - --- + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +## Step-by-Step Tutorial -
+For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# Introduction to Wormhole - -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +# Products -## What Problems Does Wormhole Solve? +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Critical problems Wormhole addresses include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## Transfer Products -## What Does Wormhole Offer? +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +
-## What Isn't Wormhole? +::spantable:: -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -## Use Cases of Wormhole +::end-spantable:: -Consider the following examples of potential applications enabled by Wormhole: +
-- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -## Explore +## Real-time Data -Discover more about the Wormhole ecosystem, components, and protocols: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +## Multichain Governance -## Demos +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# Architecture - +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -!!! note - Wormhole Integration Complete? +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Supported Blockchains + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Wormhole supports a growing number of blockchains. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - - -
+## On-Chain Components -### EVM +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Off-Chain Components -### SVM +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Core Contracts** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. -### Move VM + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -### Sui Move VM + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Security +# Core Contracts -## Core Security Assumptions +## Introduction -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -In summary: +## Key Functions -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Key functions of the Wormhole Core Contract include the following: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -## Guardian Network +## How the Core Contract Works -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -### Governance +The following describes the role of the Wormhole Core Contract in message transfers: -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +### Message Submission -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -Via governance, the Guardians can: +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Message Reception -## Monitoring +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +## Multicast -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -Guardians monitor: +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -## Asset Layer Protections +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +## Next Steps -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +
-In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -## Open Source + --- -Wormhole builds in the open and is always open source. + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -## Audits +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + --- -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -## Bug Bounties +
+--- END CONTENT --- -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Guardian -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +Guardians fulfill their role in the messaging protocol as follows: -## Learn More +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- +## Guardian Network -# Get Started with Core Contracts +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Introduction +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +The following sections explore each principle in detail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +### Decentralization -## Prerequisites +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -To interact with the Wormhole Core Contract, you'll need the following: +Two common approaches to decentralization have notable limitations: -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -## How to Interact with Core Contracts +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +To answer that, consider these key constraints and design decisions: -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -### Sending Messages +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +### Modularity -=== "EVM" +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +### Chain Agnosticism + +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +### Scalability - ??? interface "Parameters" +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +### Upgradeable - --- +Wormhole is designed to adapt and evolve in the following ways: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - ??? interface "Returns" +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Next Steps - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +
-// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +- :octicons-book-16:{ .lg .middle } **Relayers** -// Check fee and send parameters + --- -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -10165,245 +9706,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -10587,4 +9974,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index dd0b7e70f..18468b532 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -13,18 +13,17 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md [type: build] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md [type: build] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/build/toolkit/cli/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ --- BEGIN CONTENT --- --- title: Wormhole CLI @@ -789,7 +788,7 @@ worm info rpc mainnet bsc ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/dev-env/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ --- BEGIN CONTENT --- --- title: Local Dev Environment @@ -854,7 +853,7 @@ https://api.wormholescan.io ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/faqs/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ --- BEGIN CONTENT --- --- title: Toolkit FAQs @@ -911,41 +910,6 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/ ---- BEGIN CONTENT --- ---- -title: Wormhole SDK -description: The Wormhole SDK provides tools for cross-chain communication, token bridges, and more, enabling developers to integrate with multiple blockchain environments. -categories: Typescript-SDK ---- - -# Wormhole SDK - -## Get Started - -The Wormhole SDK provides developers with essential tools for cross-chain communication, token bridges, and more. This SDK enables seamless interaction between different blockchain environments with a focus on performance and usability. - -
- -- :octicons-book-16:{ .lg .middle } **Wormhole SDK** - - --- - - Learn about the core functionalities of the Wormhole SDK, including how to use its features for building cross-chain applications. - - [:custom-arrow: Explore the SDK](/docs/tools/typescript-sdk/sdk-reference/) - -- :octicons-code-16:{ .lg .middle } **Layouts** - - --- - - Discover how to define, serialize, and deserialize data structures using the Wormhole SDK's layout system, ensuring efficient cross-chain communication. - - [:custom-arrow: Learn about layouts](/docs/tools/typescript-sdk/guides/sdk-layout/) - -
---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ --- BEGIN CONTENT --- --- @@ -3522,2154 +3486,2026 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. categories: Basics --- -# Glossary +# Wormhole Use Cases -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +
+
-## Chain ID +## Cross-Chain Swaps and Liquidity Aggregation -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +Enable seamless swaps between chains with real-time liquidity routing. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +
+
-## Consistency Level +🛠 **Wormhole products used:** -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -## Delivery Provider +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +
+
-## Emitter -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +
+
-## Finality +## Borrowing and Lending Across Chains -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +Let users borrow assets on one chain using collateral from another. -## Guardian +
+
-A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +🛠 **Wormhole products used:** -## Guardian Network +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -## Guardian Set +
+
-The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -## Heartbeat +
+
-Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +## Real-Time Price Feeds and Trading Strategies -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +Fetch price feeds across multiple chains for DeFi applications. -## Observation +
+
-An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +🛠 **Wormhole products used:** -## Relayer +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -A relayer is any process that delivers VAAs to a destination. +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} -## Sequence +
+
-A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. -## Spy +
+
-A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +## Asset Movement Between Bitcoin and Other Chains -## VAA +Enable direct BTC transfers without wrapped assets. -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +
+
-## Validator +🛠 **Wormhole products used:** -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} -# Infrastructure Components +
+
-This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +
+
-## Get Started +## Decentralized Social Platforms -Start here for an overview of Wormhole architecture components and security mechanisms: +Enable seamless communication and asset transfer across decentralized social networks. -
+
+
-- :octicons-book-16:{ .lg .middle } **Architecture Overview** +🛠 **Wormhole products used:** - --- +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +
+
-- :octicons-book-16:{ .lg .middle } **Security** - --- +
+
- Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +## Memecoin Launchpads - [:custom-arrow: Learn About Security](/docs/protocol/security/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-## Explore Components +🛠 **Wormhole products used:** -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +
+
-## Next Steps -
+
+
-- :octicons-book-16:{ .lg .middle } **Messaging Components** +## Cross-Chain Perpetuals - --- +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +
+
- [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +🛠 **Wormhole products used:** -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - --- +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +
+
- [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) -
---- END CONTENT --- +
+
-Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +## Gas Abstraction -# Architecture +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. -## Overview +
+
-Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +🛠 **Wormhole products used:** -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +
+
- The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +
+
-## On-Chain Components +## Bridging Intent Library -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. -## Off-Chain Components +
+
-- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +🛠 **Wormhole products used:** -## Next Steps +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents -
+🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -- :octicons-book-16:{ .lg .middle } **Core Contracts** +
+
- --- - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +
+
- [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +## Multichain Prediction Markets -- :octicons-tools-16:{ .lg .middle } **Core Messaging** +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - --- +
+
- Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +🛠 **Wormhole products used:** + +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- -# Core Contracts +
+
-## Introduction +## Cross-Chain Payment Widgets -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +
+
-## Key Functions +🛠 **Wormhole products used:** -Key functions of the Wormhole Core Contract include the following: +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - -## How the Core Contract Works - -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. - -The following describes the role of the Wormhole Core Contract in message transfers: - -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions - -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - -### Message Submission - -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +
+
-### Message Reception -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +
+
-## Multicast +## Oracle Networks -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +
+
-This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +🛠 **Wormhole products used:** -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -## Next Steps +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -
+
+
-- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - --- +
+
- Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +## Cross-Chain Staking - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +Enable users to stake assets on one chain while earning rewards or securing networks on another. -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +
+
- --- +🛠 **Wormhole products used:** - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/..learn/glossary/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. categories: Basics --- -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +# Glossary -The following sections explore each principle in detail. +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -### Decentralization +## Chain ID -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -Two common approaches to decentralization have notable limitations: +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +## Consistency Level -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +## Delivery Provider -To answer that, consider these key constraints and design decisions: +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +## Emitter -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. -### Modularity +## Finality -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. -### Chain Agnosticism +## Guardian -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -### Scalability +## Guardian Network -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## Guardian Set -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. -### Upgradeable +## Heartbeat -Wormhole is designed to adapt and evolve in the following ways: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Observation -## Next Steps +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. -
+## Relayer -- :octicons-book-16:{ .lg .middle } **Relayers** +A relayer is any process that delivers VAAs to a destination. - --- +## Sequence - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +## Spy -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - --- +## VAA - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +## Validator -
+A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts categories: Basics --- -# Relayers +# Get Started with Core Contracts -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Introduction -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -There are three primary types of relayers discussed: +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +## Prerequisites -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +To interact with the Wormhole Core Contract, you'll need the following: -## Fundamentals +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +## How to Interact with Core Contracts -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -Key characteristics of VAAs include: +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network -- Public emission from the Guardian Network +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. -- Authentication through signatures from the Guardian Network +### Sending Messages -- Verifiability by any entity or any Wormhole Core Contract +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. +=== "EVM" -Keep in mind the following security considerations around relayers: + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly + ??? interface "Parameters" -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Client-Side Relaying + --- -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -### Key Features + --- -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure + ??? interface "Returns" -### Implementation + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -Users themselves carry out the three steps of the cross-chain process: + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -1. Perform an action on chain A +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -2. Retrieve the resulting VAA from the Guardian Network +// Check fee and send parameters -3. Perform an action on chain B using the VAA +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); -### Considerations - -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - -- Users must sign all required transactions with their own wallet - -- Users must have funds to pay the transaction fees on every chain involved - -- The user experience may be cumbersome due to the manual steps involved - -## Custom Relayers - -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - -### Key Features - -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application - -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - -### Implementation - -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - -### Considerations - -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - -- Development work and hosting of relayers are required - -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - -- Relayers are responsible for availability, and adding dependencies for the cross-chain application - -## Wormhole Relayers - -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. - -### Key Features - -- **Lower operational costs** - no need to develop, host, or maintain individual relayers - -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); -### Implementation +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -The Wormhole relayer integration involves two key steps: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +=== "Solana" -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -### Considerations + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. + ??? interface "Parameters" -- All computations are performed on-chain + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- Potentially less gas-efficient compared to custom relayers + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -- Support may not be available for all chains + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -## Next Steps + ??? child "Type `PostMessage<'info>`" -
+ ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -- :octicons-book-16:{ .lg .middle } **Spy** + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - --- + --- - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. + `batch_id` ++"u32"++ + + An identifier for the message batch. - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + --- -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. - --- + --- - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - --- + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -
---- END CONTENT --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -# Spy +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. +### Receiving Messages -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. +The way a message is received and handled depends on the environment. -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. +=== "EVM" -## Key Features + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -## Integrator Use Case + ??? interface "Parameters" -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ??? interface "Returns" -## Observable Message Categories + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -A Spy can access the following categories of messages shared over the gossip protocol: + ??? child "Struct `VM`" -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status + ??? interface "Example" - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## Additional Resources + // Perform safety checks here -
+ // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + // Your custom application logic here +} + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. +=== "Solana" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + Retrieve the raw message data: - --- + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. + ??? interface "Example" - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` - --- + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +#### Validating the Emitter - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -
+Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -## Next Steps +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -
+This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -- :octicons-code-16:{ .lg .middle } **Run a Spy** +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); - --- +await tx.wait(); +``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +#### Additional Checks - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -- :octicons-code-16:{ .lg .middle } **Use Queries** +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? - --- +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. +## Source Code References - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -
+- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. +# Wormhole Relayer -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. +## Introduction -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. +## Get Started with the Wormhole Relayer -## VAA Format +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -The basic VAA consists of header and body components described as follows: +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
- Where each `signature` is: +### Wormhole Relayer Interfaces - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +## Interact with the Wormhole Relayer -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -## Consistency and Finality +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +Your initial set up should resemble the following: -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Signatures +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. +contract Example { + IWormholeRelayer public wormholeRelayer; -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} ``` -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Be aware of the following considerations when working with attestations: +### Send a Message -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -### Token Transfer with Message +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +### Receive a Message -### Governance +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -#### Action Structure +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +## Delivery Guarantees -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -#### Actions +## Delivery Statuses -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -## Lifetime of a Message +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) +## Other Considerations -## Next Steps +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -
+- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -- :octicons-book-16:{ .lg .middle } **Guardians** +## Track the Progress of Messages with the Wormhole CLI - --- +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +=== "Mainnet" - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +=== "Testnet" - --- + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +## Step-by-Step Tutorial -
+For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/introduction/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# Introduction to Wormhole - -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +# Products -## What Problems Does Wormhole Solve? +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -Critical problems Wormhole addresses include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## Transfer Products -## What Does Wormhole Offer? +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +
-## What Isn't Wormhole? +::spantable:: -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -## Use Cases of Wormhole +::end-spantable:: -Consider the following examples of potential applications enabled by Wormhole: +
-- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -## Explore +## Real-time Data -Discover more about the Wormhole ecosystem, components, and protocols: +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +## Multichain Governance -## Demos +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# Architecture - +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -!!! note - Wormhole Integration Complete? +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -## Supported Blockchains + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -Wormhole supports a growing number of blockchains. + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - - -
+## On-Chain Components -### EVM +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Off-Chain Components -### SVM +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +## Next Steps -### AVM +
-| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-book-16:{ .lg .middle } **Core Contracts** -### CosmWasm + --- -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. -### Move VM + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -### NEAR VM + --- -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -### Sui Move VM + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. categories: Basics --- -# Security +# Core Contracts -## Core Security Assumptions +## Introduction -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. -In summary: +## Key Functions -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Key functions of the Wormhole Core Contract include the following: -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -## Guardian Network +## How the Core Contract Works -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -### Governance +The following describes the role of the Wormhole Core Contract in message transfers: -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +### Message Submission -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: -Via governance, the Guardians can: +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Message Reception -## Monitoring +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +## Multicast -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -Guardians monitor: +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -## Asset Layer Protections +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +## Next Steps -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +
-In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** -## Open Source + --- -Wormhole builds in the open and is always open source. + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -## Audits +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + --- -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) -## Bug Bounties +
+--- END CONTENT --- -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Guardian -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +Guardians fulfill their role in the messaging protocol as follows: -## Learn More +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics ---- +## Guardian Network -# Get Started with Core Contracts +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. -## Introduction +The Guardian Network is designed to help Wormhole deliver on five key principles: -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +The following sections explore each principle in detail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +### Decentralization -## Prerequisites +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. -To interact with the Wormhole Core Contract, you'll need the following: +Two common approaches to decentralization have notable limitations: -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment -## How to Interact with Core Contracts +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network +To answer that, consider these key constraints and design decisions: -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -### Sending Messages +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +### Modularity -=== "EVM" +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +### Chain Agnosticism + +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` +### Scalability - ??? interface "Parameters" +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +### Upgradeable - --- +Wormhole is designed to adapt and evolve in the following ways: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - ??? interface "Returns" +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +## Next Steps - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +
-// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); +- :octicons-book-16:{ .lg .middle } **Relayers** -// Check fee and send parameters + --- -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + --- -=== "Solana" + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +# Relayers - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +There are three primary types of relayers discussed: - ??? child "Type `PostMessage<'info>`" +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - --- +## Fundamentals - `batch_id` ++"u32"++ - - An identifier for the message batch. +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - --- +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +Key characteristics of VAAs include: - --- +- Public emission from the Guardian Network - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- Authentication through signatures from the Guardian Network - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +- Verifiability by any entity or any Wormhole Core Contract - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters +Keep in mind the following security considerations around relayers: -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. +## Client-Side Relaying -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -### Receiving Messages +### Key Features -The way a message is received and handled depends on the environment. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -=== "EVM" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +### Implementation - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +Users themselves carry out the three steps of the cross-chain process: - ??? interface "Parameters" +1. Perform an action on chain A - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +2. Retrieve the resulting VAA from the Guardian Network - ??? interface "Returns" +3. Perform an action on chain B using the VAA - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +### Considerations - ??? child "Struct `VM`" +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +- Users must sign all required transactions with their own wallet - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +- Users must have funds to pay the transaction fees on every chain involved - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +- The user experience may be cumbersome due to the manual steps involved - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +## Custom Relayers - ??? interface "Example" +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Perform safety checks here +### Key Features - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - // Your custom application logic here -} - ``` +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -=== "Solana" +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +### Implementation - Retrieve the raw message data: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +### Considerations - ??? interface "Example" +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +- Development work and hosting of relayers are required - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -#### Validating the Emitter +## Wormhole Relayers -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +### Key Features -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +### Implementation -await tx.wait(); -``` +The Wormhole relayer integration involves two key steps: -#### Additional Checks +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +### Considerations -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Source Code References +- All computations are performed on-chain -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +- Potentially less gas-efficient compared to custom relayers -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +- Support may not be available for all chains -# Wormhole Relayer +## Next Steps -## Introduction +
-The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +- :octicons-book-16:{ .lg .middle } **Spy** -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + --- -## Get Started with the Wormhole Relayer + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+ --- -### Wormhole Relayer Interfaces + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -## Interact with the Wormhole Relayer + --- -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +
+--- END CONTENT --- -Your initial set up should resemble the following: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +# Spy -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract Example { - IWormholeRelayer public wormholeRelayer; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +## Key Features -### Send a Message +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +## Integrator Use Case -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Observable Message Categories -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); -``` +A Spy can access the following categories of messages shared over the gossip protocol: -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -### Receive a Message +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` +## Additional Resources -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +
-## Delivery Guarantees +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + --- -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -## Delivery Statuses +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + --- -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + --- -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. -## Other Considerations + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: +
-- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent +## Next Steps -## Track the Progress of Messages with the Wormhole CLI +
-While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +- :octicons-code-16:{ .lg .middle } **Run a Spy** -=== "Mainnet" + --- - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -=== "Testnet" + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +- :octicons-code-16:{ .lg .middle } **Use Queries** -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + --- -## Step-by-Step Tutorial + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/start-building/products/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ --- BEGIN CONTENT --- --- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics --- -# Products +# Verified Action Approvals -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -## Transfer Products +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +## VAA Format -
+The basic VAA consists of header and body components described as follows: -::spantable:: +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + Where each `signature` is: -::end-spantable:: + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -
+- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -## Real-time Data +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -## Multichain Governance +## Consistency and Finality -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -# Wormhole Use Cases +## Signatures -
-
+The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -## Cross-Chain Swaps and Liquidity Aggregation +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -Enable seamless swaps between chains with real-time liquidity routing. +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -
-
+## Payload Types -🛠 **Wormhole products used:** +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution +### Token Transfer -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -
-
+Transferring tokens from the sending chain to the destination chain requires the following steps: + +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -## Borrowing and Lending Across Chains +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -Let users borrow assets on one chain using collateral from another. +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -
-
+### Attestation -🛠 **Wormhole products used:** +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +The message format for token attestation is as follows: -
-
+- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset +#### Attestation Tips -
-
+Be aware of the following considerations when working with attestations: -## Real-Time Price Feeds and Trading Strategies +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -Fetch price feeds across multiple chains for DeFi applications. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -
-
+- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -🛠 **Wormhole products used:** +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +### Token Transfer with Message -
-
+The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior -
-
+This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: -## Asset Movement Between Bitcoin and Other Chains +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -Enable direct BTC transfers without wrapped assets. +### Governance -
-
+Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). -🛠 **Wormhole products used:** +#### Action Structure + +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: + +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action + +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. + +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` + +#### Actions + +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: + +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains +## Lifetime of a Message -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -
-
+With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -
-
+1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step -## Decentralized Social Platforms +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -Enable seamless communication and asset transfer across decentralized social networks. +## Next Steps -
-
+
-🛠 **Wormhole products used:** +- :octicons-book-16:{ .lg .middle } **Guardians** -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + --- -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -
-
+ [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** -
-
+ --- -## Memecoin Launchpads + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/)
-
+--- END CONTENT --- -🛠 **Wormhole products used:** +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +# Introduction to Wormhole -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -
-
+Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. -
-
+![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) -## Cross-Chain Perpetuals +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. -
-
+This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. -🛠 **Wormhole products used:** +## What Problems Does Wormhole Solve? -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +Critical problems Wormhole addresses include: -
-
+- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +## What Does Wormhole Offer? -
-
+Wormhole provides a suite of tools and protocols that support a wide range of use cases: -## Gas Abstraction +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +## What Isn't Wormhole? -
-
+- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -🛠 **Wormhole products used:** +## Use Cases of Wormhole -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments +Consider the following examples of potential applications enabled by Wormhole: -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -
-
+## Explore +Discover more about the Wormhole ecosystem, components, and protocols: -
-
+- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -## Bridging Intent Library +## Demos -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +Demos offer more realistic implementations than tutorials: -
-
+- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -🛠 **Wormhole products used:** + -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +!!! note + Wormhole Integration Complete? -
-
+ Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** -
-
+## Supported Blockchains -## Multichain Prediction Markets +Wormhole supports a growing number of blockchains. -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + + +
-
-
+### EVM -🛠 **Wormhole products used:** +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +### SVM -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### AVM +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
-
+### CosmWasm -## Cross-Chain Payment Widgets +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +### Move VM -
-
+| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🛠 **Wormhole products used:** +### NEAR VM -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +### Sui Move VM +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
-
- + +--- END CONTENT --- -
-
+Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- -## Oracle Networks +# Security -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +## Core Security Assumptions -
-
+At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -🛠 **Wormhole products used:** +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +In summary: -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit -
-
+Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +## Guardian Network -
-
+Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -## Cross-Chain Staking +### Governance -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -
-
+This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -🛠 **Wormhole products used:** +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +Via governance, the Guardians can: -
-
---- END CONTENT --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations -## Reference Concepts [shared: true] +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. -The following section contains reference material for Wormhole. -It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. -While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. +## Monitoring ---- +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -## List of shared concept pages: +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +Guardians monitor: -## Full content for shared concepts: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- +## Asset Layer Protections -# Reference +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -## Get Started +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -
+## Open Source -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** +Wormhole builds in the open and is always open source. - --- +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. +## Audits - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} - --- +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. +## Bug Bounties - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. - --- +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. - This includes the following protocol contracts: +## Learn More - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) +## Reference Concepts [shared: true] -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** +The following section contains reference material for Wormhole. +It includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. +While it may not be required for all use cases, it offers a deeper technical layer for advanced development work. - --- +--- - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. +## List of shared concept pages: - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) -
---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- @@ -6103,245 +5939,91 @@ categories: Reference === "Testnet" | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +=== "Devnet" -=== "Solana" + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +## CCTP -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + + -The result is a standardized address format that is ready for cross-chain operations. +=== "Mainnet" -### Convert Back to Native Addresses + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: +=== "Testnet" -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` +=== "Devnet" -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + N/A + + -## Use Cases for Wormhole Formatted Addresses +## Settlement Token Router -### Cross-chain Token Transfers +=== "Mainnet" -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -### Smart Contract Interactions +=== "Testnet" -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -### DApp Development +## Read-Only Deployments -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +=== "Mainnet" -### Relayers and Infrastructure + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ @@ -6525,4 +6207,158 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Sui | Sui Move VM | SUI | List of Faucets |
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- + +# Wormhole Formatted Addresses + +## Introduction + +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. + +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. + +## Platform-Specific Address Formats + +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. + +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: + +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | + +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. + +### Address Format Handling + +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` + +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + +## Universal Address Methods + +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + +Key functions: + + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` + + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` + + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform + + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` + + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations + + ```typescript + console.log(universalAddress.toString()); + ``` + +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. + +## Convert Between Native and Wormhole Formatted Addresses + +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. + +### Convert a Native Address to a Wormhole Formatted Address + +Example conversions for EVM and Solana: + +=== "EVM" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` + +=== "Solana" + + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; + +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` + +The result is a standardized address format that is ready for cross-chain operations. + +### Convert Back to Native Addresses + +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); + +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` + +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + +## Use Cases for Wormhole Formatted Addresses + +### Cross-chain Token Transfers + +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. + +### Smart Contract Interactions + +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. + +### DApp Development + +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. + +### Relayers and Infrastructure + +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- \ No newline at end of file diff --git a/llms-full.txt b/llms-full.txt index 756a000d7..f30cbc05b 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -6,10881 +6,7335 @@ Wormhole. A cross-chain messaging protocol used to move data and assets between Documentation: https://wormhole.com/docs/ ## List of doc pages: +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/core-messaging/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/construct-a-query.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/mock-a-query.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/query-request.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/index.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/tutorials/.settlement-routes.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-relayer.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/index.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.settlement-routes.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/..build/core-messaging/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics +title: Core Messaging Layer Contracts +description: Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. --- -# Get Started with Core Contracts +# Core Messaging -## Introduction +Wormhole-deployed relayers and Core Contracts are essential for sending and receiving multichain messages. Learning to work directly with these building blocks offers a deeper understanding of Wormhole and increased control and customization options. -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +Follow the links below for how-to guides about using Core Contracts and Wormhole-deployed relayers to send, receive, validate, and track multichain messages. -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +## Simplified Message Flow -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -## Prerequisites +Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. -To interact with the Wormhole Core Contract, you'll need the following: +[timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +## Next Steps -## How to Interact with Core Contracts +
-Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +- :octicons-tools-16:{ .lg .middle} **Get Started with Core Contracts** -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network + --- -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. + Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. -### Sending Messages + [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +- :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** -=== "EVM" + --- - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: + Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); - ``` + [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) - ??? interface "Parameters" +
+--- END CONTENT --- - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. +Doc-Content: https://wormhole.com/docs/..build/multigov/ +--- BEGIN CONTENT --- +--- +title: Getting Started with MultiGov +description: Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. +categories: MultiGov +--- - --- +# MultiGov - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. +## Begin the MultiGov Integration Process - --- +Take the following steps to get started with a MultiGov integration: - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. +1. Evaluate if [MultiGov](/docs/learn/governance/) meets your cross-chain governance needs +2. Fill out the intake form on the [Tally website](https://www.tally.xyz/get-started){target=\_blank} +3. The Tally team will review your application and contact you to discuss implementation details +4. Work with the Tally team to customize and deploy MultiGov for your specific use case - ??? interface "Returns" +## Start Building - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +
- ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); +- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); + --- -// Check fee and send parameters + Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); +- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` + --- - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. + Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. -=== "Solana" + [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: +- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` + --- - ??? interface "Parameters" + Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). + [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` + --- - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. + Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - ??? child "Type `PostMessage<'info>`" + [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +- :octicons-question-16:{ .lg .middle } **Technical FAQs** - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. + --- - --- + Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - `batch_id` ++"u32"++ - - An identifier for the message batch. + [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) - --- +
- `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +## Additional Resources - --- +
- `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +- :octicons-book-16:{ .lg .middle } **What is MultiGov?** - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" - - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" - - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters - -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. + --- -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. + Need to familiarize yourself with MultiGov? Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. + [:custom-arrow: Learn the basics](/docs/learn/governance/) -### Receiving Messages +- :octicons-checklist-16:{ .lg .middle } **Tutorials** -The way a message is received and handled depends on the environment. + --- -=== "EVM" + Access step-by-step tutorials for executing cross-chain governance actions, including treasury management proposals with MultiGov. - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. + [:custom-arrow: Learn by building](/docs/tutorials/multigov/) - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` +
+--- END CONTENT --- - ??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/..build/queries/overview/ +--- BEGIN CONTENT --- +--- +title: Queries Overview +description: Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. +categories: Queries +--- - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. +# Queries Overview {: #queries-overview } - ??? interface "Returns" +Wormhole Guardians, who run full nodes for various connected chains, facilitate a new cross-chain query service that allows for on-demand attested responses to queries, bypassing the inefficiencies of traditional transaction-based data retrieval. This method is faster and cost-effective, eliminating the need for gas payments and transaction finality wait times. - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. +!!! note + Queries are currently in closed beta, though you can start developing today. Check out [Use Queries](/docs/build/queries/use-queries/){target=\_blank} and reach out to [Join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. - ??? child "Struct `VM`" +Wormhole Queries offers on-demand access to Guardian-attested on-chain data. The current implementation provides integrators with a simple REST endpoint to initiate an off-chain request via a proxy. The proxy then forwards the request to the Guardians and gathers a quorum of responses. The result returns the encoded response, including the request details and the Guardian signatures. The request validation performed by the query module includes a three step process that involves verifying the signature to ensure it has the correct prefix, confirming that the signer is authorized to execute query requests, and validating the legitimacy of all per-chain requests contained in the query. You can read more about Queries in the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank}. - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` +## The Flow of a Query {: #the-flow-of-a-query} - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +The general overview of a query's flow is as follows: an off-chain process sends HTTPS query requests to a Query Proxy, which validates and forwards them to the Guardians; these Guardians independently validate, sign, and return the response, with the entire process typically taking less than a second. - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +![The architecture flow of a query](/docs/images/build/queries/overview/overview-1.webp) - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +The step-by-step flow of a query is as follows: - ??? interface "Example" +1. An off-chain process initiates a query request via HTTPS to the query proxy (or Query Server) +2. The query proxy validates the request and forwards it to the Guardians via a gossip network +3. The Guardians independently validate the request, make the requisite RPC calls, verify the results, sign, and gossip a response back to the Query Proxy +4. The Query Proxy aggregates the results and returns a response when it reaches a quorum of two-thirds or more of the current Guardian set - the exact quorum requirements as the core bridge +5. The off-chain process can then submit these requests to an on-chain contract which should verify the signatures and validate the request before processing the result - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +In this flow, the Query Proxy is a permissioned but trustless part of the protocol. In most cases, this entire process takes less than one second. If a request is invalid or cannot be processed by the Guardians, they will retry for up to one minute before timing out. Requests can be batched to have the Guardians make multiple calls to multiple networks. This can further reduce overhead for processing query responses on-chain. Up to 255 queries can be batched together, with certain types allowing for batching themselves. - // Perform safety checks here +## Supported Query Types {: #supported-query-types} - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); +There are currently five supported types of queries. See [the white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank} for more details on each. - // Your custom application logic here -} - ``` +### eth_call {: #eth-call} - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +This query type is effectively an equivalent of [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a block specified by number or hash. -=== "Solana" +Calls are batched to allow specifying multiple calls (even to multiple contracts) against the same block. These calls are included in a single batch RPC call, simplifying on-chain verification. Up to 255 calls may be batched in an single `eth_call` query. - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. +The result contains the specified block number, hash, timestamp, and the call result. - Retrieve the raw message data: +### eth_call By Timestamp {: #eth-call-by-timestamp} - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +This query type is similar to `eth_call` but targets a timestamp instead of a specific `block_id`. This can be useful when forming requests based on uncorrelated data, such as requiring data from another chain based on the block timestamp of a given chain. - ??? interface "Example" +The result also contains the target and block details with the following enforced conditions: `target_block.timestamp <= target_time < following_block.timestamp` and `following_block_num - 1 == target_block_num`. - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted +### eth_call With Finality {: #eth-call-with-finality} - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) - } -} - - ``` +This query type is similar to `eth_call` but ensures that the specified block has reached the specified finality before returning the query results. The finality may be `finalized` or `safe.` Note that if a chain doesn't natively support the `safe` tag, this will be equivalent to `finalized.` - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. +### sol_account {: #sol_account} -#### Validating the Emitter +This query is used to read data for one or more accounts on Solana, akin to [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank}. -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. +### sol_pda {: #sol_pda} -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: +This query is used to read data for one or more [Program Derived Addresses(PDA)](https://www.anchor-lang.com/docs/pdas){target=\_blank} on Solana, akin to calling [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} on the result of `PublicKey.findProgramAddressSync(seeds, programId).` This query is helpful for times when you want to more generally read accounts owned by a program and verify the derivation on another chain, like how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` +## Supported Chains {: #supported-chains} -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +The following table provides expected support based on testing. However, the success of any given query is based on the success of the underlying call on each Guardian’s RPC node. -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); +For example, many chains have implementations forked from [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which keeps 128 blocks of state in memory by default (without running in archive mode). While this is good for about 25 minutes of history on Ethereum Mainnet, it is only about three minutes on Optimism. While Guardian nodes can be expected to have access to recent state, there are currently no guarantees of how far back in history they have access to. -await tx.wait(); -``` +### Mainnet {: #mainnet} -#### Additional Checks +| Chain | Wormhole Chain ID | eth_call | By Timestamp | With Finality | Expected History | +|:-------------:|:-----------------:|:--------:|:------------------:|:-------------:|:----------------:| +| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | +| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | +| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | +| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | +| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | +| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | +| Karura | 11 | ✅ | ✅ | ✅ | archive | +| Acala | 12 | ✅ | ✅ | ✅ | archive | +| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | +| Celo | 14 | ✅ | ℹ️ hints required\* | ✅ | 128 blocks | +| Moonbeam | 16 | ✅ | ℹ️ hints required\* | ✅ | 256 blocks | +| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | +| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | +| Base | 30 | ✅ | ✅ | ✅ | archive | -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +\*`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +## Next Steps {: #next-steps} -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. -## Source Code References +Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +You can also check out the following examples of applications that make use of Wormhole Queries: -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +- [Basic demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} +- [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} +- [Solana Program Derived Address (PDA) / Token Account Balance](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} +- [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/core-messaging/ +Doc-Content: https://wormhole.com/docs/..build/queries/use-queries/ --- BEGIN CONTENT --- --- -title: Core Messaging Layer Contracts -description: Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. +title: Use Queries +description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. +categories: Queries --- -# Core Messaging - -Wormhole-deployed relayers and Core Contracts are essential for sending and receiving multichain messages. Learning to work directly with these building blocks offers a deeper understanding of Wormhole and increased control and customization options. - -Follow the links below for how-to guides about using Core Contracts and Wormhole-deployed relayers to send, receive, validate, and track multichain messages. +# Use Queries -## Simplified Message Flow +You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. +This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. -Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. +## RPC Basics -[timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] +Before digging into anything Queries-specific, this page will look at how to make an [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a public Ethereum RPC. Suppose you'd like to query the WETH contract for its total supply; before making a request, you need some information about the contract you want to call, including: -## Next Steps +- **To** - the contract to call. WETH is [0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2){target=\_blank} +- **Data** - the method identifier and ABI-encoded parameters, which can be obtained as follows: `web3.eth.abi.encodeFunctionSignature("totalSupply()")` which yields `0x18160ddd` +- **Block ID** - the block number, hash, or tag. Tag options include `latest,` `safe,` or `finalized` -
+The prepared curl request is as follows: -- :octicons-tools-16:{ .lg .middle} **Get Started with Core Contracts** +```bash title="eth_call JSON-RPC request" +curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' +``` - --- +And the corresponding response is: - Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. +```bash title="eth_call JSON-RPC reponse" +{ + "jsonrpc":"2.0", + "id":1, + "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" +} +``` - [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) +Converting the returned value of the executed call from hexidecimal results in the value `3172615244782286193073777`. You can compare your result to the [**Read Contract**](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#readContract){target=\_blank} tab in Etherscan. Your result will be different as WETH is minted/burned over time. -- :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** +## Construct a Query {: #construct-a-query} - --- +You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. - Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. +```jsx +npm i @wormhole-foundation/wormhole-query-sdk axios +``` - [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) +In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. -
---- END CONTENT --- +You can request the latest block from a public node using `eth_getBlockByNumber`. -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- +```jsx -# Wormhole Relayer +await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; +``` -## Introduction +Then construct the call data. -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. +```jsx +to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; +``` -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. +Finally, put it all together in a `QueryRequest`. -## Get Started with the Wormhole Relayer +```jsx +const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); +``` -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. +This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. +```jsx -
- ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
The components outlined in blue must be implemented.
-
+// { +// "nonce": 0, +// "requests": [ +// { +// "chainId": 2, +// "query": { +// "callData": [ +// { +// "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", +// "data": "0x18160ddd" +// } +// ], +// "blockTag": "0x11e9068" +// } +// } +// ], +// "version": 1 +// } +``` -### Wormhole Relayer Interfaces +## Mock a Query -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: +For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from +```jsx +const mockData = await mock.mock(request); + console.log(mockData); +// { +// signatures: ['...'], +// bytes: '...' +// } +``` -## Interact with the Wormhole Relayer +This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. +```jsx +const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); +// Mock Query Result: 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee (3172556167631284394053614) +``` -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. +Testing this all together might look like the following: -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +```jsx +import { + EthCallData, + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryProxyMock, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; -Your initial set up should resemble the following: +const rpc = 'https://ethereum.publicnode.com'; +const callData: EthCallData = { + to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; +(async () => { + const latestBlock: string = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + if (!latestBlock) { + console.error(`❌ Invalid block returned`); + return; + } + console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); + const targetResponse = await axios.post(rpc, { + method: 'eth_call', + params: [callData, latestBlock], + id: 1, + jsonrpc: '2.0', + }); + // console.log(finalizedResponse.data); + if (targetResponse.data.error) { + console.error(`❌ ${targetResponse.data.error.message}`); + } + const targetResult = targetResponse.data?.result; + console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); + // Form the query request + const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); + console.log(JSON.stringify(request, undefined, 2)); + const mock = new QueryProxyMock({ 2: rpc }); + const mockData = await mock.mock(request); + console.log(mockData); + const mockQueryResponse = QueryResponse.from(mockData.bytes); + const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); +})(); +``` -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; +### Fork Testing -contract Example { - IWormholeRelayer public wormholeRelayer; +It is common to test against a local fork of Mainnet with something like - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} +```jsx +anvil --fork-url https://ethereum.publicnode.com ``` -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. - -### Send a Message +In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); +```jsx +npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe ``` -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. +## Make a Query Request -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused +The standardized means of making a `QueryRequest` with an API key is as follows: + +```jsx +const serialized = request.serialize(); +const proxyResponse = (await axios.post)( + QUERY_URL, + { + bytes: Buffer.from(serialized).toString('hex'), + }, + { headers: { 'X-API-Key': YOUR_API_KEY } } ); + ``` -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: +A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); - -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` +A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` -### Receive a Message +## Verify a Query Response On-Chain -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). +A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; +```bash +forge install wormhole-foundation/wormhole-solidity-sdk ``` -The logic inside the function body may be whatever business logic is required to take action on the specific payload. +Broadly, using a query response on-chain comes down to three main steps: -## Delivery Guarantees + 1. Parse and verify the query response + 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract + 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: + - Is the request against the expected chain? + - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing + - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks + - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases + - Is the result of the expected length for the expected result type? + 4. Run `abi.decode` on the result -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. +See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. +??? code "View the complete `QueryDemo`" + ```solidity + // contracts/query/QueryDemo.sol +// SPDX-License-Identifier: Apache 2 -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. +pragma solidity ^0.8.0; -## Delivery Statuses +import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; +import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; +import "wormhole-solidity-sdk/QueryResponse.sol"; -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: +error InvalidOwner(); +// @dev for the onlyOwner modifier +error InvalidCaller(); +error InvalidCalldata(); +error InvalidForeignChainID(); +error ObsoleteUpdate(); +error StaleUpdate(); +error UnexpectedResultLength(); +error UnexpectedResultMismatch(); -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure +/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. +contract QueryDemo is QueryResponse { + using BytesParsing for bytes; -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + struct ChainEntry { + uint16 chainID; + address contractAddress; + uint256 counter; + uint256 blockNum; + uint256 blockTime; + } -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` + address private immutable owner; + uint16 private immutable myChainID; + mapping(uint16 => ChainEntry) private counters; + uint16[] private foreignChainIDs; -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. + bytes4 public GetMyCounter = bytes4(hex"916d5743"); -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. + constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { + if (_owner == address(0)) { + revert InvalidOwner(); + } + owner = _owner; -## Other Considerations + myChainID = _myChainID; + counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); + } -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: + // updateRegistration should be used to add the other chains and to set / update contract addresses. + function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { + if (counters[_chainID].chainID == 0) { + foreignChainIDs.push(_chainID); + counters[_chainID].chainID = _chainID; + } -- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent + counters[_chainID].contractAddress = _contractAddress; + } -## Track the Progress of Messages with the Wormhole CLI + // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. + function getMyCounter() public view returns (uint256) { + return counters[myChainID].counter; + } -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: + // getState() returns this chain's view of all the counters. It is meant to be used in the front end. + function getState() public view returns (ChainEntry[] memory) { + ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); + ret[0] = counters[myChainID]; + uint256 length = foreignChainIDs.length; -=== "Mainnet" + for (uint256 i = 0; i < length;) { + ret[i + 1] = counters[foreignChainIDs[i]]; + unchecked { + ++i; + } + } - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + return ret; + } -=== "Testnet" + // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. + function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { + ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); + uint256 numResponses = r.responses.length; + if (numResponses != foreignChainIDs.length) { + revert UnexpectedResultLength(); + } - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` + for (uint256 i = 0; i < numResponses;) { + // Create a storage pointer for frequently read and updated data stored on the blockchain + ChainEntry storage chainEntry = counters[r.responses[i].chainId]; + if (chainEntry.chainID != foreignChainIDs[i]) { + revert InvalidForeignChainID(); + } -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); -## Step-by-Step Tutorial + // Validate that update is not obsolete + validateBlockNum(eqr.blockNum, chainEntry.blockNum); -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. ---- END CONTENT --- + // Validate that update is not stale + validateBlockTime(eqr.blockTime, block.timestamp - 300); -Doc-Content: https://wormhole.com/docs/build/ ---- BEGIN CONTENT --- ---- -title: Build with Wormhole -description: Learn how to start building multichain solutions on Wormhole, with tips to get started, an overview of the toolkit, and an introduction to the protocols. -template: root-index-page.html ---- + if (eqr.result.length != 1) { + revert UnexpectedResultMismatch(); + } -# Build + // Validate addresses and function signatures + address[] memory validAddresses = new address[](1); + bytes4[] memory validFunctionSignatures = new bytes4[](1); + validAddresses[0] = chainEntry.contractAddress; + validFunctionSignatures[0] = GetMyCounter; -## Quick Start: Step-by-Step Tutorials + validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); -If you learn best by building, start here to build with the Wormhole TypeScript SDK: + require(eqr.result[0].result.length == 32, "result is not a uint256"); -- [**Transfer Tokens via the Token Bridge**](/docs/products/token-bridge/tutorials/transfer-workflow/){target=\_blank} - use the [Wormhole SDK's](/docs/tools/typescript-sdk/get-started/){target=\_blank} Token Bridge method to move wrapped assets across networks + chainEntry.blockNum = eqr.blockNum; + chainEntry.blockTime = eqr.blockTime / 1_000_000; + chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); -- [**Transfer USDC via CCTP and Wormhole SDK**](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/){target=\_blank} - combine the [Wormhole SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} and Circle's Cross-Chain Transfer Protocol (CCTP) to bridge native USDC across networks + unchecked { + ++i; + } + } -Alternatively, start here to work with Wormhole contracts directly: + counters[myChainID].blockNum = block.number; + counters[myChainID].blockTime = block.timestamp; + counters[myChainID].counter += 1; + } -- [**Create Multichain Messaging Contracts**](/docs/products/messaging/tutorials/cross-chain-contracts/) - create mulitchain contracts using Wormhole's Solidity SDK. You will deploy smart contracts and send messages across chains + modifier onlyOwner() { + if (owner != msg.sender) { + revert InvalidOwner(); + } + _; + } +} + ``` -- [**Create Multichain Token Transfer Contracts**](/docs/products/messaging/tutorials/cross-chain-token-contracts/) - create multichain token transfers using Wormhole's Solidity SDK. You will build and deploy smart contracts to send tokens from one blockchain to another +## Submit a Query Response On-Chain -## Builder Essentials +The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. -Access essential information and tools quickly: +This example submits the transaction to the demo contract: -
+```jsx +const tx = await contract.updateCounters( + `0x${response.data.bytes}`, + signaturesToEvmStruct(response.data.signatures) +); +``` +--- END CONTENT --- -- :octicons-tools-16:{ .lg .middle } **Supported Networks** +Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ +--- BEGIN CONTENT --- +--- +title: Use Cases +description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +categories: Basics +--- - --- +# Wormhole Use Cases - Supported blockchains by environment - main or testnet availability and quick links to the website, documentation, and block explorer for each network. +
+
- [:custom-arrow: Supported Networks](/docs/products/reference/supported-networks/) +## Cross-Chain Swaps and Liquidity Aggregation -- :octicons-tools-16:{ .lg .middle } **Testnet Faucets** +Enable seamless swaps between chains with real-time liquidity routing. - --- +
+
- Links to testnet token faucets for supported networks. +🛠 **Wormhole products used:** - [:custom-arrow: Get Testnet Tokens](/docs/products/reference/testnet-faucets/) +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution -- :octicons-tools-16:{ .lg .middle } **Wormhole TypeScript SDK** +🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - --- +
+
- Your guide to Wormhole SDK installation and usage, concepts overview, and code samples. - [:custom-arrow: Wormhole TypeScript SDK](/docs/tools/typescript-sdk/sdk-reference/) +
+
-- :octicons-tools-16:{ .lg .middle } **Reference** +## Borrowing and Lending Across Chains - --- +Let users borrow assets on one chain using collateral from another. - Wormhole chain ID, contract address, address formatting and conversion, and consistency information. +
+
- [:custom-arrow: Reference](/docs/products/reference/) +🛠 **Wormhole products used:** -
+- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time -## Integrate Transfer Products +🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} -
+
+
-- :octicons-tools-16:{ .lg .middle } **Multichain Transfers** - --- +
+
- - **Connect UI widget** - easy-to-use UI for multichain asset transfers via Wormhole in a web application - - **Native Token Transfers (NTT)** - native asset transfer, without the need for wrapped assets - - **Token Bridge** - transfer wrapped assets with optional message payloads - - **Settlement** - intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more +## Real-Time Price Feeds and Trading Strategies - [:custom-arrow: Build Multichain Transfers](/docs/build/transfers/) +Fetch price feeds across multiple chains for DeFi applications.
+
-## Access Real-Time Data +🛠 **Wormhole products used:** -
+- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades -- :octicons-tools-16:{ .lg .middle } **Real-Time Data** +🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - --- +
+
+ + +
+
- - **Wormhole Queries** - on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy - - **Supported query types** - includes query equivalents for `eth_call` (with options for timestamp and finality), `sol_account`, and `sol_pda` - - **Use familiar endpoints** - make calls against the RPC provider endpoints you already know and use +## Asset Movement Between Bitcoin and Other Chains - [:custom-arrow: Build with Queries](/docs/build/queries/) +Enable direct BTC transfers without wrapped assets.
+
-## Multichain Governance +🛠 **Wormhole products used:** -
+- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains -- :octicons-tools-16:{ .lg .middle } **MultiGov** +🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - --- +
+
- - **Wormhole's MultiGov** - a multichain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks - - **Hub-and-spoke model** - spoke chain contracts handle local voting and proposals with results sent to the hub for vote aggregation and tallying, proposal management, and coordinating governance across connected chains - - **Wormhole security** - moving vote weight checkpoints, timelocks, and Wormhole verification keep governance activity secure +
+
- [:custom-arrow: Build with MultiGov](/docs/build/multigov/) +## Decentralized Social Platforms -
---- END CONTENT --- +Enable seamless communication and asset transfer across decentralized social networks. -Doc-Content: https://wormhole.com/docs/build/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Run Infrastructure Services -description: Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. -# template: root-index-page.html ---- +
+
-# Infrastructure +🛠 **Wormhole products used:** -## Get Started +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions +- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards -Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. +🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} -
+
+
-- :octicons-terminal-16:{ .lg .middle } **Relayers** - --- +
+
- Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. +## Memecoin Launchpads - [:custom-arrow: Run a relayer](/docs/protocol/infrastructure-guides/run-relayer/) +Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access.
+
-
+🛠 **Wormhole products used:** + +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes -- :octicons-terminal-16:{ .lg .middle } **Spy** +🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - --- +
+
+ + +
+
- Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. +## Cross-Chain Perpetuals - [:custom-arrow: Run a Spy](/docs/protocol/infrastructure-guides/run-spy/) +Enable leveraged perpetual trading across chains with seamless collateral and liquidity management.
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/build/infrastructure/relayers/ ---- BEGIN CONTENT --- ---- -title: Relayers -description: Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. -categories: Relayers ---- +🛠 **Wormhole products used:** -# Relayers +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences -## Get Started +🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives -
+
+
-- :octicons-terminal-16:{ .lg .middle } **Run a Custom Relayer** - --- +
+
+ +## Gas Abstraction - This section guides you through developing your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. +Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. + +
+
-
+🛠 **Wormhole products used:** - Benefits of running your own relayer: +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - - You can add logic to customize the delivery of messages - - You can perform off-chain computations resulting in optimized gas costs +🔗 **Used in:** Wallets, dApps, and multichain user experience improvements -
+
+
- Requirements for running your own relayer: - - You are responsible for developing and hosting your relayer - - You are responsible for paying target chain fees - - You are responsible for the liveness of your relayer +
+
-
+## Bridging Intent Library - [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-relayer/) +Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic.
+
-## Additional Resources +🛠 **Wormhole products used:** -
+- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents + +🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries -- :octicons-question-16:{ .lg .middle } **What is a Relayer?** +
+
- --- - Learn about what a relayer is, what role it plays in the delivery of cross-chain messages, and the different types of relayers in the Wormhole ecosystem. +
+
+ +## Multichain Prediction Markets - [:custom-arrow: Learn more about relayers](/docs/protocol/infrastructure/relayer/) +Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. -- :octicons-gear-16:{ .lg .middle } **Simplify the Development Process** +
+
- --- +🛠 **Wormhole products used:** - Use the Wormhole Relayer Engine package as a foundational toolkit to develop your own customized off-chain relaying service, enabling tailored message handling. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains +- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - [:custom-arrow: Check out the Relayer Engine source code](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} +🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming
---- END CONTENT --- +
-Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ ---- BEGIN CONTENT --- ---- -title: Run a Relayer -description: Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -categories: Relayers ---- -# Run a Custom Relayer +
+
-## Introduction +## Cross-Chain Payment Widgets -Relayers play a crucial role in cross-chain communication, ensuring that messages are transferred seamlessly between different blockchains. While Wormhole relayers provide a reliable way to handle these transfers, they might not always meet every application's unique requirements. +Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. -Custom relayers address these limitations by offering tailored solutions that cater to the distinct needs of your application. Developing a custom relayer gives you complete control over message processing, delivery mechanisms, and integration with existing systems. This customization allows for optimized performance and the ability to implement specific features that Wormhole-deployed relayers might not support. +
+
-A custom relayer might be as simple as an in-browser process that polls the API for the availability of a VAA after submitting a transaction and delivers it to the target chain. It might also be implemented with a Spy coupled with some daemon listening for VAAs from a relevant chain ID and emitter, then taking action when one is observed. +🛠 **Wormhole products used:** -This guide teaches you how to set up and configure a custom relayer for efficient message handling. You'll start by understanding how to uniquely identify a VAA using its emitter address, sequence ID, and chain ID. Then, you'll explore the Relayer Engine, a package that provides a framework for building custom relayers, and learn how to fetch and handle VAAs using the Wormhole SDK. +- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers -## Get Started with a Custom Relayer +🔗 **Used in:** E-commerce, Web3 payments, and subscription models -To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs. +
+
-
- ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp) -
The off-chain components outlined in blue must be implemented.
-
-### How to Uniquely Identify a VAA +
+
-Regardless of the environment, to get the VAA you intend to relay, you need: +## Oracle Networks -- The `emitter` address -- The `sequence` ID of the message you're interested in -- The `chainId` for the chain that emitted the message +Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. -With these three components, you're able to uniquely identify a VAA and process it. +
+
-## Use the Relayer Engine +🛠 **Wormhole products used:** -The [`relayer-engine`](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} is a package that provides the structure and a starting point for a custom relayer. +- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks -With the Relayer Engine, a developer can write specific logic for filtering to receive only the messages they care about. +🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} -Once a Wormhole message is received, the developer may apply additional logic to parse custom payloads or submit the Verifiable Action Approvals (VAA) to one or many destination chains. +
+
-To use the Relayer Engine, a developer may specify how to relay Wormhole messages for their app using an idiomatic Express/Koa middleware-inspired API, then let the library handle all the details. -### Install the Relayer Engine +
+
-First, install the `relayer-engine` package with your favorite package manager: +## Cross-Chain Staking -```bash -npm i @wormhole-foundation/relayer-engine -``` +Enable users to stake assets on one chain while earning rewards or securing networks on another. -### Get Started with the Relayer Engine +
+
-In the following example, you'll: +🛠 **Wormhole products used:** -1. Set up a `StandardRelayerApp`, passing configuration options for our relayer -2. Add a filter to capture only those messages our app cares about, with a callback to do _something_ with the VAA once received -3. Start the relayer app +- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains +- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks -```typescript -import { - Environment, - StandardRelayerApp, - StandardRelayerContext, -} from '@wormhole-foundation/relayer-engine'; -import { CHAIN_ID_SOLANA } from '@certusone/wormhole-sdk'; +🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} -(async function main() { - // Initialize relayer engine app and pass relevant config options - const app = new StandardRelayerApp( - Environment.TESTNET, - // Other app specific config options can be set here for things - // like retries, logger, or redis connection settings - { - name: 'ExampleRelayer', - } - ); +
+
+--- END CONTENT --- - // Add a filter with a callback that will be invoked - // on finding a VAA that matches the filter - app.chain(CHAIN_ID_SOLANA).address( - // Emitter address on Solana - 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', - // Callback function to invoke on new message - async (ctx, next) => { - const vaa = ctx.vaa; - const hash = ctx.sourceTxHash; - console.log( - `Got a VAA with sequence: ${vaa.sequence} from with txhash: ${hash}` - ); - } - ); +Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ +--- BEGIN CONTENT --- +--- +title: Wormhole CLI +description: Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. +categories: Solidity-SDK, Typescript-SDK +--- - // Add and configure any other middleware here +# Wormhole CLI - // Start app. Blocks until unrecoverable error or process is stopped - await app.listen(); -})(); - +This tool is a command-line interface to Wormhole, allowing you to perform various actions, such as querying a transaction's status or submitting token transfers. + +## Installation + +Clone the repository and change directories to the appropriate directory: + +```bash +git clone https://github.com/wormhole-foundation/wormhole && +cd wormhole/clients/js ``` -The first meaningful line instantiates the `StandardRelayerApp`, a subclass of the `RelayerApp` with standard defaults. +Build and install the CLI tool: -```typescript -export class StandardRelayerApp< - ContextT extends StandardRelayerContext = StandardRelayerContext, -> extends RelayerApp { - // ... - constructor(env: Environment, opts: StandardRelayerAppOpts) { +```bash +make install ``` -The only field you pass in the `StandardRelayerAppOpts` is the name to help identify log messages and reserve a namespace in Redis. +This installs two binaries, `worm-fetch-governance` and `worm` on your `$PATH`. To use `worm`, set up `$HOME/.wormhole/.env` with your private keys, based on `.env.sample` in this folder. -??? code "`StandardRelayerAppOpts`" +## Usage - Other options can be passed to the `StandardRelayerApp` constructor to configure the app further. +You can interact with the Wormhole CLI by typing `worm` and including the `command` and any necessary subcommands and parameters. - ```typescript - wormholeRpcs?: string[]; // List of URLs from which to query missed VAAs -concurrency?: number; // How many concurrent requests to make for workflows -spyEndpoint?: string; // The hostname and port of our Spy -logger?: Logger; // A custom Logger -privateKeys?: Partial<{ [k in ChainId]: any[]; }>; // A set of keys that can be used to sign and send transactions -tokensByChain?: TokensByChain; // The token list we care about -workflows?: { retries: number; }; // How many times to retry a given workflow -providers?: ProvidersOpts; // Configuration for the default providers -fetchSourceTxhash?: boolean; // whether or not to get the original transaction ID/hash -// Redis config -redisClusterEndpoints?: ClusterNode[]; -redisCluster?: ClusterOptions; -redis?: RedisOptions; - ``` - -The next meaningful line in the example adds a filter middleware component. This middleware will cause the relayer app to request a subscription from the Spy for any VAAs that match the criteria and invoke the callback with the VAA. +| Command | Description | +|--------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| +| `worm aptos INSERT_COMMAND` | Aptos utilities | +| `worm edit-vaa INSERT_COMMAND` | Edits or generates a VAA | +| `worm evm INSERT_COMMAND` | EVM utilities | +| `worm generate INSERT_COMMAND` | Generate VAAs (Devnet and Testnet only) | +| `worm info INSERT_COMMAND` | Contract, chain, RPC, and address information utilities | +| `worm near INSERT_NETWORK, INSERT_ACCOUNT` | NEAR utilities | +| `worm parse INSERT_VAA` | Parse a VAA (can be in either hex or base64 format) | +| `worm recover INSERT_DIGEST INSERT_SIGNATURE` | Recover an address from a signature | +| `worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH` | Prints information about the automatic delivery initiated on the specified network, chain, and transaction hash | +| `worm submit INSERT_VAA` | Execute a VAA | +| `worm sui INSERT_COMMAND` | Sui utilities | +| `worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK` | Transfers a token | +| `worm verify-vaa INSERT_VAA, INSERT_NETWORK` | Verifies a VAA by querying the Core Contract on Ethereum | -If you'd like your program to subscribe to `multiple` chains and addresses, you can call the same method several times or use the `multiple` helper. +You can also refer to the below options, available with all `worm` commands: -```typescript -app.multiple( - { - [CHAIN_ID_SOLANA]: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', - [CHAIN_ID_ETH]: ['0xabc1230000000...', '0xdef456000...'], - }, - myCallback -); +```bash +Options: + --help Show help [boolean] + --version Show version number [boolean] ``` -The last line in the simple example runs `await app.listen()`, which starts the relayer engine. Once started, the Relayer Engine issues subscription requests to the Spy and begins any other workflows (e.g., tracking missed VAAs). - -This will run until the process is killed or encounters an unrecoverable error. To gracefully shut down the relayer, call `app.stop()`. +### Subcommands -The source code for this example is available in the [`relayer-engine` repository](https://github.com/wormhole-foundation/relayer-engine/blob/main/examples/simple/src/app.ts){target=\_blank}. +??? code "Aptos" + ```bash + worm aptos INSERT_COMMAND -## Start Background Processes +Commands: + worm aptos init-token-bridge Init token bridge contract + worm aptos init-wormhole Init Wormhole core contract + worm aptos deploy Deploy an Aptos package + worm aptos deploy-resource Deploy an Aptos package using a + resource account + worm aptos send-example-message Send example message + + worm aptos derive-resource-account Derive resource account address + + worm aptos derive-wrapped-address Derive wrapped coin type + + worm aptos hash-contracts Hash contract bytecodes for upgrade + worm aptos upgrade Perform upgrade after VAA has been + submitted + worm aptos migrate Perform migration after contract + upgrade + worm aptos faucet Request money from the faucet for a + given account + worm aptos start-validator Start a local aptos validator -!!! note - These processes _must_ be running for the relayer app below to work. +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` -Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. +??? code "Edit VAA" + ```bash + worm edit-vaa INSERT_COMMAND -More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. +Options: + --help Show help [boolean] + --version Show version number [boolean] + -v, --vaa vaa in hex format [string] [required] + -n, --network Network + [required] [choices: "mainnet", "testnet", "devnet"] + --guardian-set-index, --gsi guardian set index [number] + --signatures, --sigs comma separated list of signatures [string] + --wormscanurl, --wsu url to wormscan entry for the vaa that + includes signatures [string] + --wormscan, --ws if specified, will query the wormscan entry + for the vaa to get the signatures [boolean] + --emitter-chain-id, --ec emitter chain id to be used in the vaa + [number] + --emitter-address, --ea emitter address to be used in the vaa[string] + --nonce, --no nonce to be used in the vaa [number] + --sequence, --seq sequence number to be used in the vaa[string] + --consistency-level, --cl consistency level to be used in the vaa + [number] + --timestamp, --ts timestamp to be used in the vaa in unix + seconds [number] + -p, --payload payload in hex format [string] + --guardian-secret, --gs Guardian's secret key [string] + ``` -### Wormhole Network Spy +??? code "EVM" + ```bash + worm evm INSERT_COMMAND -For our relayer app to receive messages, a local Spy must be running that watches the Guardian network. Our relayer app will receive updates from this Spy. +Commands: + worm evm address-from-secret Compute a 20 byte eth address from a 32 + byte private key + worm evm storage-update Update a storage slot on an EVM fork + during testing (anvil or hardhat) + worm evm chains Return all EVM chains + worm evm info Query info about the on-chain state of + the contract + worm evm hijack Override the guardian set of the core + bridge contract during testing (anvil + or hardhat) + worm evm start-validator Start a local EVM validator -=== "Mainnet Spy" +Options: + --help Show help [boolean] + --version Show version number [boolean] + --rpc RPC endpoint [string] + ``` +??? code "Generate" ```bash - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env mainnet - ``` + worm generate INSERT_COMMAND -=== "Testnet Spy" +Commands: + worm generate registration Generate registration VAA + worm generate upgrade Generate contract upgrade VAA + worm generate attestation Generate a token attestation VAA + worm generate recover-chain-id Generate a recover chain ID VAA + worm generate Sets the default delivery provider + set-default-delivery-provider for the Wormhole Relayer contract - ```bash - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env testnet +Options: + --help Show help [boolean] + --version Show version number [boolean] + -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] ``` -### Redis Persistence +??? code "Info" + ```bash + worm info INSERT_COMMAND -!!! note - While you're using [Redis](https://redis.io/docs/latest/develop/get-started/){target=\_blank} here, the persistence layer can be swapped out for some other database by implementing the appropriate [interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank}. +Commands: + worm info chain-id Print the wormhole chain ID integer + associated with the specified chain + name + worm info contract Print contract address + + worm info emitter
Print address in emitter address + format + worm info origin
Print the origin chain and address + of the asset that corresponds to the + given chain and address. + worm info registrations Print chain registrations + + worm info rpc Print RPC address + worm info wrapped Print the wrapped address on the + target chain that corresponds with + the specified origin chain and + address. -A Redis instance must also be available to persist job data for fetching VAAs from the Spy. +Options: + --help Show help [boolean] + --version Show version number [boolean]
+ ``` -```bash -docker run --rm -p 6379:6379 --name redis-docker -d redis -``` +??? code "NEAR" + ```bash + worm near INSERT_COMMAND -## Use the Wormhole SDK +Commands: + worm near contract-update Submit a contract update using our specific + APIs + worm near deploy Submit a contract update using near APIs -!!! note - The example below uses the legacy [`@certusone/wormhole-sdk`](https://www.npmjs.com/package/@certusone/wormhole-sdk){target=\_blank}, which is still supported and used in the Relayer Engine but is no longer actively maintained. - - For most use cases, it is recommend to use the latest [`@wormhole-foundation/sdk`](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}. +Options: + --help Show help [boolean] + --version Show version number [boolean] + -m, --module Module to query [choices: "Core", "NFTBridge", "TokenBridge"] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + --account Near deployment account [string] [required] + --attach Attach some near [string] + --target Near account to upgrade [string] + --mnemonic Near private keys [string] + --key Near private key [string] + -r, --rpc Override default rpc endpoint url [string] + ``` -You can also use the Wormhole SDK to poll the Guardian RPC until a signed VAA is ready using the SDK's `getSignedVAAWithRetry` function. +??? code "Parse" + ```bash + worm parse INSERT_VAA -```ts -import { - getSignedVAAWithRetry, - parseVAA, - CHAIN_ID_SOLANA, - CHAIN_ID_ETH, -} from '@certusone/wormhole-sdk'; +Positionals: + vaa vaa [string] -const RPC_HOSTS = [ - /* ...*/ -]; +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` -async function getVAA( - emitter: string, - sequence: string, - chainId: number -): Promise { - // Wait for the VAA to be ready and fetch it from the guardian network - const { vaaBytes } = await getSignedVAAWithRetry( - RPC_HOSTS, - chainId, - emitter, - sequence - ); - return vaaBytes; -} +??? code "Recover" + ```bash + worm recover INSERT_DIGEST INSERT_SIGNATURE -const vaaBytes = await getVAA('INSERT_EMITTER_ADDRESS', 1, CHAIN_ID_ETH); - -``` - -Once you have the VAA, the delivery method is chain-dependent. - -=== "EVM" - - On EVM chains, the bytes for the VAA can be passed directly as an argument to an ABI method. - - ```ts - // Set up eth wallet -const ethProvider = new ethers.providers.StaticJsonRpcProvider( - 'INSERT_RPC_URL' -); -const ethWallet = new ethers.Wallet('INSERT_PRIVATE_KEY', ethProvider); - -// Create client to interact with our target app -const ethHelloWorld = HelloWorld__factory.connect( - 'INSERT_CONTRACT_ADDRESS', - ethWallet -); - -// Invoke the receiveMessage on the ETH contract and wait for confirmation -const receipt = await ethHelloWorld - .receiveMessage(vaaBytes) - .then((tx: ethers.ContractTransaction) => tx.wait()) - .catch((msg: any) => { - console.error(msg); - return null; - }); - ``` - -=== "Solana" - - On Solana, the VAA is first posted to the core bridge, and then a custom transaction is prepared to process and validate the VAA. - - ```ts - import { CONTRACTS } from '@certusone/wormhole-sdk'; - -export const WORMHOLE_CONTRACTS = CONTRACTS[NETWORK]; -export const CORE_BRIDGE_PID = new PublicKey(WORMHOLE_CONTRACTS.solana.core); - -// First, post the VAA to the core bridge -await postVaaSolana( - connection, - wallet.signTransaction, - CORE_BRIDGE_PID, - wallet.key(), - vaaBytes -); - -const program = createHelloWorldProgramInterface(connection, programId); -const parsed = isBytes(wormholeMessage) - ? parseVaa(wormholeMessage) - : wormholeMessage; - -const ix = program.methods - .receiveMessage([...parsed.hash]) - .accounts({ - payer: new PublicKey(payer), - config: deriveConfigKey(programId), - wormholeProgram: new PublicKey(wormholeProgramId), - posted: derivePostedVaaKey(wormholeProgramId, parsed.hash), - foreignEmitter: deriveForeignEmitterKey(programId, parsed.emitterChain), - received: deriveReceivedKey( - programId, - parsed.emitterChain, - parsed.sequence - ), - }) - .instruction(); - -const transaction = new Transaction().add(ix); -const { blockhash } = await connection.getLatestBlockhash(commitment); -transaction.recentBlockhash = blockhash; -transaction.feePayer = new PublicKey(payerAddress); - -const signed = await wallet.signTxn(transaction); -const txid = await connection.sendRawTransaction(signed); +Positionals: + digest digest [string] + signature signature [string] -await connection.confirmTransaction(txid); +Options: + --help Show help [boolean] + --version Show version number [boolean] ``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover everything you need to about the Wormhole Spy, a daemon that watches the Guardian Network and subscribe to signed messages. ---- - -# Spy - -## Get Started - -
- -- :octicons-terminal-16:{ .lg .middle } **Run a Spy** - - --- - - The content in this section shows you how you can run your own infrastructure and spin up a Spy daemon locally to subscribe to a stream of messages, also known as Verifiable Action Approvals (VAAs). - - [:custom-arrow: Get started now](/docs/protocol/infrastructure-guides/run-spy/) - -
- -## Additional Resources - -
- -- :octicons-question-16:{ .lg .middle } **What is a Spy?** - - --- - - Learn about what a Spy is and what role it plays in the delivery of cross-chain messages. - - [:custom-arrow: Learn more about Spies](/docs/protocol/infrastructure/spy/) - -- :octicons-code-16:{ .lg .middle } **Interact with a Spy** - - --- - - Use the Wormhole Spy SDK to subscribe to the stream of signed messages. - - [:custom-arrow: Use the Wormhole Spy SDK](https://github.com/wormhole-foundation/wormhole/blob/main/spydk/js/README.md){target=\_blank} - -- :octicons-bookmark-16:{ .lg .middle } **Alternative Implementations** - - --- - - Check out Beacon, an alternative highly available version of the Wormhole Spy. - - [:custom-arrow: Use Pyth Beacon](https://github.com/pyth-network/beacon){target=\_blank} - -
---- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-spy/ ---- BEGIN CONTENT --- ---- -title: Run a Spy -description: Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. ---- - -# Run a Spy - -## Introduction - -The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. - -For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. - -## How to Start a Spy - -To start a Spy locally, run the following Docker command: - -=== "Mainnet" - - ```sh - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env mainnet - ``` +??? code "Status" + ```bash + worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH -=== "Testnet" +Positionals: + network Network [choices: + 'mainnet', + 'testnet', + 'devnet'] + chain Source chain + [choices: + 'unset', + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + tx Source transaction hash [string] - ```sh - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env testnet +Options: + --help Show help [boolean] + --version Show version number [boolean] ``` -If you want to run the Spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image. - -Optionally, add the following flags to skip any VAAs with invalid signatures: - -=== "Mainnet" - - ```sh - --ethRPC https://eth.drpc.org - --ethContract 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B - ``` +??? code "Submit" + ```bash + worm submit INSERT_VAA -=== "Testnet" +Positionals: + vaa vaa [string] - ```sh - --ethRPC https://sepolia.drpc.org/ - --ethContract 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 - ``` - -Optionally, add the following flags to prevent unbounded log growth: - -```sh ---log-opt max-size=10m \ ---log-opt max-file=3 -``` - -## Subscribe to Filtered VAAs - -Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your program) can subscribe to a filtered stream of messages (VAAs). - -Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. - -!!! note - If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. - -## Data Persistence - -The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. - -The persistence layer needs to implement the appropriate interface. For example, you can check out the [Redis interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank} used by the Relayer Engine, a package that implements a client and persistence layer for messages received from a Spy subscription. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ ---- BEGIN CONTENT --- ---- -title: Deploy MultiGov on EVM Chains -description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. -categories: MultiGov ---- - -# Deploy MultiGov on EVM Chains - -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/build/multigov/){target=\_blank}. - -Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. - -## Prerequisites - -To interact with MultiGov, you'll need the following: - -- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} -- Install [Git](https://git-scm.com/downloads){target=\_blank} -- Clone the repository: - ```bash - git clone https://github.com/wormhole-foundation/multigov - cd evm # for evm testing/deploying - ``` - -## Development Setup - -For developers looking to set up a local MultiGov environment: - -1. Install dependencies: - ```bash - forge install - ``` - -2. Set up environment variables: - ```bash - cp .env.example .env - ``` - - Edit `.env` with your specific [configuration](#configuration){target=\_blank} - -3. Compile contracts: - ```bash - forge build - ``` - -4. Deploy contracts (example for Sepolia testnet): - - For hub chains: - ```bash - forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast - ``` - - For spoke chains (e.g., Optimism Sepolia): - ```bash - forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast - ``` - -## Configuration - -When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: - -### Hub Governor Key Parameters - -- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day -- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal -- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful -- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day - - !!! note - This helps mitigate cross-chain double voting. - -### Hub Proposal Extender Key Parameters - -- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours -- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour - -### Spoke Vote Aggregator Key Parameters - -- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day - - !!! note - This is crucial for mitigating cross-chain double voting - -### Hub Evm Spoke Vote Aggregator Key Parameters - -- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes - -### Updateable Governance Parameters - -The following key parameters can be updated through governance proposals: - -- `votingDelay` - delay before voting starts (in seconds) -- `votingPeriod` - duration of the voting period (in seconds) -- `proposalThreshold` - threshold for creating proposals (in tokens) -- `quorum` - number of votes required for quorum -- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) -- `voteWeightWindow` - window for vote weight checkpoints (in seconds) -- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time - -These parameters can be queried using their respective getter functions on the applicable contract. - -To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ ---- BEGIN CONTENT --- ---- -title: MultiGov Deployment to Solana -description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. -categories: MultiGov ---- - -# Deploy MultiGov on Solana - -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. - -Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. - -## Prerequisites - -To deploy MultiGov on Solana, ensure you have the following installed: - - - Install [Git](https://git-scm.com/downloads){target=\_blank} - - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** - - Install [Solana CLI](https://docs.anza.xyz/cli/install/){target=\_blank} **`v1.18.20`** - - Install [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`v0.30.1`** - - Install [Rust](https://www.rust-lang.org/tools/install){target=\_blank} **`v1.80.1`** - - Install [Docker](https://www.docker.com/get-started/){target=\_blank} - - Clone the repository: - ```bash - git clone https://github.com/wormhole-foundation/multigov.git - cd multigov/solana/ - ``` - -## Build the Project - -To create a verifiable build of the MultiGov Staking Program, run the following command: - -```bash -./scripts/build_verifiable_staking_program.sh -``` - -Once the build is complete, the compiled artifacts will be available in the `target` folder. - -## Set Up the Deployer Account - -For a successful deployment, you need a funded deployer account on Solana. This account will store the program and execute deployment transactions. - -In this section, you will create a new keypair, check the account balance, and ensure it has enough SOL tokens to cover deployment costs. If needed, you can fund the account using different methods before deploying. - -### Generate a New Keypair - -To create a new keypair and save it to a file, run the following command: - -```bash -solana-keygen new --outfile ./app/keypairs/deployer.json -``` - -### Check the Deployer Account Address - -To retrieve the public address of the newly created keypair, run the following command: - -```bash -solana address -k ./app/keypairs/deployer.json -``` - -### Check the Deployer Account Balance - -To verify the current balance of the deployer account, run the following command: - -```bash -solana balance -k ./app/keypairs/deployer.json -``` - -!!! warning - When deploying the MultiGov Staking Program, the deployer account must have enough SOL to cover deployment costs and transaction fees. - - - 7.60219224 SOL for deployment costs - - 0.00542 SOL for transaction fees - -### Fund the Deployer Account - -If the account does not have enough SOL, use one of the following methods to add funds. - - - **Transfer SOL from another account** - if you already have SOL in another account, transfer it using a wallet (Phantom, Solflare, etc.) or in the terminal - - ```bash - solana transfer --from /path/to/funder.json - ``` - - - **Request an airdrop (devnet only)** - if deploying to devnet, you can request free SOL - - ```bash - solana airdrop 2 -k ./app/keypairs/deployer.json - ``` - - - **Use a Solana faucet (devnet only)** - you can use online faucets to receive 10 free SOL - - - [Solana Faucet](https://faucet.solana.com/){target=\_blank} - -## Deploy the MultiGov Staking Program - -With the deployer account set up and funded, you can deploy the MultiGov Staking Program to the Solana blockchain. This step involves deploying the program, verifying the deployment, and ensuring the necessary storage and metadata are correctly configured. Once the IDL is initialized, the program will be ready for further setup and interaction. - -### Deploy the Program - -Deploy the MultiGov Staking Program using Anchor: - -```bash -anchor deploy --provider.cluster https://api.devnet.solana.com --provider.wallet ./app/keypairs/deployer.json -``` - -### Verify the Deployment - -After deployment, check if the program is successfully deployed by running the following command: - -```bash -solana program show INSERT_PROGRAM_ID -``` - -### Extend Program Storage - -If the deployed program requires additional storage space for updates or functionality, extend the program storage using the following command: - -```bash -solana program extend INSERT_PROGRAM_ID 800000 -``` - -### Initialize the IDL - -To associate an IDL file with the deployed program, run the following command: - -```bash -anchor idl init --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json INSERT_PROGRAM_ID -``` - -## Configure the Staking Program - -The final step after deploying the MultiGov Staking Program is configuring it for proper operation. This includes running a series of deployment scripts to initialize key components and set important governance parameters. These steps ensure that staking, governance, and cross-chain communication function as expected. - -### Run Deployment Scripts - -After deploying the program and initializing the IDL, execute the following scripts **in order** to set up the staking environment and necessary accounts. - -1. Initialize the MultiGov Staking Program with default settings: - - ```bash - npx ts-node app/deploy/01_init_staking.ts - ``` - -2. Create an Account Lookup Table (ALT) to optimize transaction processing: - - ```bash - npx ts-node app/deploy/02_create_account_lookup_table.ts - ``` - -3. Set up airlock accounts: - - ```bash - npx ts-node app/deploy/03_create_airlock.ts - ``` - -4. Deploy a metadata collector: - - ```bash - npx ts-node app/deploy/04_create_spoke_metadata_collector.ts - ``` - -5. Configure vote weight window lengths: - - ```bash - npx ts-node app/deploy/05_initializeVoteWeightWindowLengths.ts - ``` - -6. Deploy the message executor for handling governance messages: - - ```bash - npx ts-node app/deploy/06_create_message_executor.ts - ``` - -### Set MultiGov Staking Program Key Parameters - -When deploying MultiGov on Solana, several key parameters need to be set. Here are the most important configuration points: - - - `maxCheckpointsAccountLimit` ++"u64"++ - the maximum number of checkpoints an account can have. For example, `654998` is used in production, while `15` might be used for testing - - `hubChainId` `u16` - the chain ID of the hub network where proposals are primarily managed. For example, `10002` for Sepolia testnet - - `hubProposalMetadata` ++"[u8; 20]"++ - an array of bytes representing the address of the Hub Proposal Metadata contract on Ethereum. This is used to identify proposals from the hub - - `voteWeightWindowLength` ++"u64"++ - specifies the length of the checkpoint window in seconds in which the minimum voting weight is taken. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The vote weight window helps solve problems such as manipulating votes in a chain - - `votingTokenMint` ++"Pubkey"++ - the mint address of the token used for voting - - `governanceAuthority` ++"Pubkey"++ - the account's public key with the authority to govern the staking system. The `governanceAuthority` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup - - `vestingAdmin` ++"Pubkey"++ - the account's public key for managing vesting operations. The `vestingAdmin` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup - - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ ---- BEGIN CONTENT --- ---- -title: MultiGov Technical FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -categories: MultiGov ---- - -# FAQs - -## Technical Questions - -### How does MultiGov ensure security in cross-chain communication? - -MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: - -- Message origin verification to prevent unauthorized governance actions -- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states -- Authorized participant validation to maintain the integrity of the governance process -- Replay attack prevention by tracking executed messages - -### Can MultiGov integrate with any blockchain? - -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. - -### How are votes aggregated across different chains? - -Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. - -### Can governance upgrade from a single chain to MultiGov? - -Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. - -## Usage Questions - -### How can I create a proposal in MultiGov? - -Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. - -### How do I vote on a proposal if I hold tokens on a spoke chain? - -You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. - -### How are approved proposals executed across multiple chains? - -When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. - -## Implementation Questions - -### What are the requirements for using MultiGov? - -To use MultiGov, your DAO must meet the following requirements: - -- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance -- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature - -### What do I need to set up MultiGov for my project? - -Get started by filling out the form below: - -https://www.tally.xyz/get-started - -Tally will reach out to help get your DAO set up with MultiGov. - -To set up testing MultiGov for your DAO, you'll need: - -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed -- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) -- Modify and deploy the hub and spoke contracts using the provided scripts -- Set up the necessary environment variables and configurations - -### Can MultiGov be used with non-EVM chains? - -The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. - -### How can I customize voting parameters in MultiGov? - -Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. - -Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. - -### How does MultiGov handle potential network issues or temporary chain unavailability? - -MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: - -1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable -2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems -3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through -4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline - -However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/multigov/ ---- BEGIN CONTENT --- ---- -title: Getting Started with MultiGov -description: Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -categories: MultiGov ---- - -# MultiGov - -## Begin the MultiGov Integration Process - -Take the following steps to get started with a MultiGov integration: - -1. Evaluate if [MultiGov](/docs/learn/governance/) meets your cross-chain governance needs -2. Fill out the intake form on the [Tally website](https://www.tally.xyz/get-started){target=\_blank} -3. The Tally team will review your application and contact you to discuss implementation details -4. Work with the Tally team to customize and deploy MultiGov for your specific use case - -## Start Building - -
- -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** - - --- - - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** - - --- - - Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** - - --- - - Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - -- :octicons-question-16:{ .lg .middle } **Technical FAQs** - - --- - - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **What is MultiGov?** - - --- - - Need to familiarize yourself with MultiGov? Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. - - [:custom-arrow: Learn the basics](/docs/learn/governance/) - -- :octicons-checklist-16:{ .lg .middle } **Tutorials** - - --- - - Access step-by-step tutorials for executing cross-chain governance actions, including treasury management proposals with MultiGov. - - [:custom-arrow: Learn by building](/docs/tutorials/multigov/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ ---- BEGIN CONTENT --- ---- -title: Upgrading MultiGov on EVM -description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. -categories: MultiGov ---- - -# Upgrade MultiGov Contracts on EVM Chains - -MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. - -## Key Considerations for Upgrades - -- **`HubGovernor`**: - - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details - -- **`HubVotePool`**: - - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` - - Requires re-registering all spokes on the new `HubVotePool` - - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` - - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` - -- **`SpokeMessageExecutor`**: - - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern - - Stores critical parameters in `SpokeMessageExecutorStorage` - -- **`HubEvmSpokeAggregateProposer`**: - - Needs redeployment if `HubGovernor` changes - - Requires re-registering all spokes after redeployment - -- **`HubProposalMetadata`**: - - Needs redeployment if `HubGovernor` changes, as it references `HubGovernor` as a parameter - -- **`SpokeMetadataCollector`**: - - Requires redeployment if the hub chain ID changes or if `HubProposalMetadata` changes - -## Process for Major System Upgrade - -1. **New `HubGovernor` deployment**: - - Deploy the new `HubGovernor` contract -1. **Component redeployment**: - - Redeploy `HubEvmSpokeAggregateProposer` with the new `HubGovernor` address - - Redeploy `HubProposalMetadata` referencing the new `HubGovernor` - - If hub chain ID changes, redeploy `SpokeMetadataCollector` on all spoke chains -1. **`HubVotePool` update**: - - Set the new `HubVotePool` on the new `HubGovernor` - - Register all spokes on the new `HubVotePool` - - Register the query type and implementation for vote decoding (`HubEvmSpokeVoteDecoder`) -1. **Spoke re-registration**: - - Re-register all spokes on the new `HubEvmSpokeAggregateProposer` -1. **Verification and testing**: - - Conduct thorough testing of the new system setup - - Verify all cross-chain interactions are functioning correctly -1. **System transition and deprecation**: - - Create a proposal to switch the timelock to the new governor - - Communicate clearly to the community what changes were made -1. **Monitoring**: - - Implement a transition period where the new system is closely monitored - - Address any issues that arise promptly - -## Important Considerations - -- Always prioritize system stability, upgrades should only be performed when absolutely necessary -- Thoroughly audit all new contract implementations before proposing an upgrade -- Account for all affected components across all chains in the upgrade plan -- Provide comprehensive documentation for the community about the upgrade process and any changes in functionality -- Always test upgrades extensively on testnets before implementing in production ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ ---- BEGIN CONTENT --- ---- -title: Upgrading MultiGov on Solana -description: Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. -categories: MultiGov ---- - -# Upgrade MultiGov Contracts on Solana - -The MultiGov Staking Program on Solana is designed to be upgradeable while maintaining stability. Upgrades introduce improvements, bug fixes, and new features but must be carefully planned and executed to prevent disruptions. - -This guide covers the key considerations and step-by-step process for upgrading the MultiGov Staking Program, including updating the program binary, Interface Description Language (IDL), and `HubProposalMetadata` while ensuring cross-chain compatibility. - -## Key Considerations for Upgrades - -- **Program upgradeability** - you can upgrade the MultiGov Staking Program on Solana using the `anchor upgrade` command - - You need the program's new bytecode (`.so` file) and an updated IDL file to reflect any changes in the program's interface to complete an upgrade - - The program's authority (deployer) must execute the upgrade - -- **`HubProposalMetadata`** - can be updated without redeploying the entire program. You can do this by invoking the `updateHubProposalMetadata` instruction - - You must carefully validate updates to `HubProposalMetadata` to ensure compatibility with the existing system - -- **Cross-chain compatibility** - ensure any changes to the Solana program do not break compatibility with the Ethereum-based `HubGovernor` - - Test upgrades thoroughly on devnet before deploying to mainnet - -## Upgrade the MultiGov Program - -Follow these steps to upgrade the MultiGov Staking Program on Solana: - -1. **Prepare the new program binary** - build the updated program using the provided script - - ```bash - ./scripts/build_verifiable_staking_program.sh - ``` - - The new program binary will be located at: - - ```bash - target/deploy/staking.so - ``` - -2. **Upgrade the program** - use the anchor upgrade command to deploy the new program binary - - ```bash - anchor upgrade --program-id INSERT_PROGRAM_ID --provider.cluster INSERT_CLUSTER_URL INSERT_PATH_TO_PROGRAM_BINARY - ``` - - Your completed anchor upgrade command should resemble the following: - ```bash - anchor upgrade --program-id DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY --provider.cluster https://api.devnet.solana.com ./target/deploy/staking.so - ``` - -3. **Update the IDL** - after upgrading the program, update the IDL to reflect any changes in the program's interface - - ```bash - anchor idl upgrade INSERT_PROGRAM_ID --filepath INSERT_PATH_TO_IDL_FILE - ``` - - Your completed IDL upgrade command should resemble the following: - ```bash - anchor idl upgrade --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY - ``` - -4. **Update `HubProposalMetadata`** - if `HubProposalMetadata` requires an update, run the following script to invoke the `updateHubProposalMetadata` instruction and apply the changes - - ```bash - npx ts-node app/deploy/07_update_HubProposalMetadata.ts - ``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/queries/faqs/ ---- BEGIN CONTENT --- ---- -title: Queries FAQs -description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. -categories: Queries ---- - -# Wormhole Queries FAQs - -## What libraries are available to handle queries? - - - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses - -- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case - -- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests - -- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses - -!!! note - A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. - -## Are there any query examples? - -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - -- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} - -## What is the format of the response signature? - -The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: - -```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` - -See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. - -!!! note - If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. - -## Can anyone run a query proxy server? - -Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. - -It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. - -## What Does Queries Offer over an RPC Service - -Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/queries/ ---- BEGIN CONTENT --- ---- -title: Wormhole Queries -description: Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. -categories: Queries ---- - -# Queries - -## Get Started - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. - -
- -- :octicons-book-16:{ .lg .middle } **Overview** - - --- - - Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST API endpoint, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Learn about Queries](/docs/build/queries/overview/) - -- :octicons-code-16:{ .lg .middle } **Use Queries** - - --- - - Explore a simple demo of interacting with Wormhole Queries using an `eth_call` request to query the supply of wETH on Ethereum using a Wormhole query. - - [:custom-arrow: Get hands-on](/docs/build/queries/use-queries/) - -- :octicons-book-16:{ .lg .middle } **Query FAQs** - - --- - - Explore frequently asked questions about Wormhole Queries. - - [:custom-arrow: Check out the FAQs](/docs/products/queries/faqs/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/queries/overview/ ---- BEGIN CONTENT --- ---- -title: Queries Overview -description: Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -categories: Queries ---- - -# Queries Overview {: #queries-overview } - -Wormhole Guardians, who run full nodes for various connected chains, facilitate a new cross-chain query service that allows for on-demand attested responses to queries, bypassing the inefficiencies of traditional transaction-based data retrieval. This method is faster and cost-effective, eliminating the need for gas payments and transaction finality wait times. - -!!! note - Queries are currently in closed beta, though you can start developing today. Check out [Use Queries](/docs/build/queries/use-queries/){target=\_blank} and reach out to [Join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data. The current implementation provides integrators with a simple REST endpoint to initiate an off-chain request via a proxy. The proxy then forwards the request to the Guardians and gathers a quorum of responses. The result returns the encoded response, including the request details and the Guardian signatures. The request validation performed by the query module includes a three step process that involves verifying the signature to ensure it has the correct prefix, confirming that the signer is authorized to execute query requests, and validating the legitimacy of all per-chain requests contained in the query. You can read more about Queries in the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank}. - -## The Flow of a Query {: #the-flow-of-a-query} - -The general overview of a query's flow is as follows: an off-chain process sends HTTPS query requests to a Query Proxy, which validates and forwards them to the Guardians; these Guardians independently validate, sign, and return the response, with the entire process typically taking less than a second. - -![The architecture flow of a query](/docs/images/build/queries/overview/overview-1.webp) - -The step-by-step flow of a query is as follows: - -1. An off-chain process initiates a query request via HTTPS to the query proxy (or Query Server) -2. The query proxy validates the request and forwards it to the Guardians via a gossip network -3. The Guardians independently validate the request, make the requisite RPC calls, verify the results, sign, and gossip a response back to the Query Proxy -4. The Query Proxy aggregates the results and returns a response when it reaches a quorum of two-thirds or more of the current Guardian set - the exact quorum requirements as the core bridge -5. The off-chain process can then submit these requests to an on-chain contract which should verify the signatures and validate the request before processing the result - -In this flow, the Query Proxy is a permissioned but trustless part of the protocol. In most cases, this entire process takes less than one second. If a request is invalid or cannot be processed by the Guardians, they will retry for up to one minute before timing out. Requests can be batched to have the Guardians make multiple calls to multiple networks. This can further reduce overhead for processing query responses on-chain. Up to 255 queries can be batched together, with certain types allowing for batching themselves. - -## Supported Query Types {: #supported-query-types} - -There are currently five supported types of queries. See [the white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank} for more details on each. - -### eth_call {: #eth-call} - -This query type is effectively an equivalent of [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a block specified by number or hash. - -Calls are batched to allow specifying multiple calls (even to multiple contracts) against the same block. These calls are included in a single batch RPC call, simplifying on-chain verification. Up to 255 calls may be batched in an single `eth_call` query. - -The result contains the specified block number, hash, timestamp, and the call result. - -### eth_call By Timestamp {: #eth-call-by-timestamp} - -This query type is similar to `eth_call` but targets a timestamp instead of a specific `block_id`. This can be useful when forming requests based on uncorrelated data, such as requiring data from another chain based on the block timestamp of a given chain. - -The result also contains the target and block details with the following enforced conditions: `target_block.timestamp <= target_time < following_block.timestamp` and `following_block_num - 1 == target_block_num`. - -### eth_call With Finality {: #eth-call-with-finality} - -This query type is similar to `eth_call` but ensures that the specified block has reached the specified finality before returning the query results. The finality may be `finalized` or `safe.` Note that if a chain doesn't natively support the `safe` tag, this will be equivalent to `finalized.` - -### sol_account {: #sol_account} - -This query is used to read data for one or more accounts on Solana, akin to [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank}. - -### sol_pda {: #sol_pda} - -This query is used to read data for one or more [Program Derived Addresses(PDA)](https://www.anchor-lang.com/docs/pdas){target=\_blank} on Solana, akin to calling [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} on the result of `PublicKey.findProgramAddressSync(seeds, programId).` This query is helpful for times when you want to more generally read accounts owned by a program and verify the derivation on another chain, like how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. - -## Supported Chains {: #supported-chains} - -The following table provides expected support based on testing. However, the success of any given query is based on the success of the underlying call on each Guardian’s RPC node. - -For example, many chains have implementations forked from [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which keeps 128 blocks of state in memory by default (without running in archive mode). While this is good for about 25 minutes of history on Ethereum Mainnet, it is only about three minutes on Optimism. While Guardian nodes can be expected to have access to recent state, there are currently no guarantees of how far back in history they have access to. - -### Mainnet {: #mainnet} - -| Chain | Wormhole Chain ID | eth_call | By Timestamp | With Finality | Expected History | -|:-------------:|:-----------------:|:--------:|:------------------:|:-------------:|:----------------:| -| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | -| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | -| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | -| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | -| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | -| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | -| Karura | 11 | ✅ | ✅ | ✅ | archive | -| Acala | 12 | ✅ | ✅ | ✅ | archive | -| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | -| Celo | 14 | ✅ | ℹ️ hints required\* | ✅ | 128 blocks | -| Moonbeam | 16 | ✅ | ℹ️ hints required\* | ✅ | 256 blocks | -| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | -| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | -| Base | 30 | ✅ | ✅ | ✅ | archive | - -\*`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. - -## Next Steps {: #next-steps} - -Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. - -Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. - -You can also check out the following examples of applications that make use of Wormhole Queries: - -- [Basic demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/queries/use-queries/ ---- BEGIN CONTENT --- ---- -title: Use Queries -description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -categories: Queries ---- - -# Use Queries - -You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. - -This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. - -## RPC Basics - -Before digging into anything Queries-specific, this page will look at how to make an [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a public Ethereum RPC. Suppose you'd like to query the WETH contract for its total supply; before making a request, you need some information about the contract you want to call, including: - -- **To** - the contract to call. WETH is [0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2){target=\_blank} -- **Data** - the method identifier and ABI-encoded parameters, which can be obtained as follows: `web3.eth.abi.encodeFunctionSignature("totalSupply()")` which yields `0x18160ddd` -- **Block ID** - the block number, hash, or tag. Tag options include `latest,` `safe,` or `finalized` - -The prepared curl request is as follows: - -```bash title="eth_call JSON-RPC request" -curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' -``` - -And the corresponding response is: - -```bash title="eth_call JSON-RPC reponse" -{ - "jsonrpc":"2.0", - "id":1, - "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" -} -``` - -Converting the returned value of the executed call from hexidecimal results in the value `3172615244782286193073777`. You can compare your result to the [**Read Contract**](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#readContract){target=\_blank} tab in Etherscan. Your result will be different as WETH is minted/burned over time. - -## Construct a Query {: #construct-a-query} - -You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. - -```jsx -npm i @wormhole-foundation/wormhole-query-sdk axios -``` - -In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. - -You can request the latest block from a public node using `eth_getBlockByNumber`. - -```jsx - -await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; -``` - -Then construct the call data. - -```jsx -to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; -``` - -Finally, put it all together in a `QueryRequest`. - -```jsx -const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); -``` - -This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. - -```jsx - -// { -// "nonce": 0, -// "requests": [ -// { -// "chainId": 2, -// "query": { -// "callData": [ -// { -// "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", -// "data": "0x18160ddd" -// } -// ], -// "blockTag": "0x11e9068" -// } -// } -// ], -// "version": 1 -// } -``` - -## Mock a Query - -For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. - -```jsx -const mockData = await mock.mock(request); - console.log(mockData); -// { -// signatures: ['...'], -// bytes: '...' -// } -``` - -This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. - -```jsx -const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -// Mock Query Result: 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee (3172556167631284394053614) -``` - -Testing this all together might look like the following: - -```jsx -import { - EthCallData, - EthCallQueryRequest, - EthCallQueryResponse, - PerChainQueryRequest, - QueryProxyMock, - QueryRequest, - QueryResponse, -} from '@wormhole-foundation/wormhole-query-sdk'; -import axios from 'axios'; - -const rpc = 'https://ethereum.publicnode.com'; -const callData: EthCallData = { - to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; - -(async () => { - const latestBlock: string = ( - await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; - if (!latestBlock) { - console.error(`❌ Invalid block returned`); - return; - } - console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); - const targetResponse = await axios.post(rpc, { - method: 'eth_call', - params: [callData, latestBlock], - id: 1, - jsonrpc: '2.0', - }); - // console.log(finalizedResponse.data); - if (targetResponse.data.error) { - console.error(`❌ ${targetResponse.data.error.message}`); - } - const targetResult = targetResponse.data?.result; - console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); - // Form the query request - const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); - console.log(JSON.stringify(request, undefined, 2)); - const mock = new QueryProxyMock({ 2: rpc }); - const mockData = await mock.mock(request); - console.log(mockData); - const mockQueryResponse = QueryResponse.from(mockData.bytes); - const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -})(); -``` - -### Fork Testing - -It is common to test against a local fork of Mainnet with something like - -```jsx -anvil --fork-url https://ethereum.publicnode.com -``` - -In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. - -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. - -```jsx -npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe -``` - -If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. - -## Make a Query Request - -The standardized means of making a `QueryRequest` with an API key is as follows: - -```jsx -const serialized = request.serialize(); -const proxyResponse = (await axios.post)( - QUERY_URL, - { - bytes: Buffer.from(serialized).toString('hex'), - }, - { headers: { 'X-API-Key': YOUR_API_KEY } } -); - -``` - -Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. - -A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` - -A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` - -## Verify a Query Response On-Chain - -A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: - -```bash -forge install wormhole-foundation/wormhole-solidity-sdk -``` - -Broadly, using a query response on-chain comes down to three main steps: - - 1. Parse and verify the query response - 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract - 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: - - Is the request against the expected chain? - - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing - - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks - - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases - - Is the result of the expected length for the expected result type? - 4. Run `abi.decode` on the result - -See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. - -??? code "View the complete `QueryDemo`" - ```solidity - // contracts/query/QueryDemo.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; -import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "wormhole-solidity-sdk/QueryResponse.sol"; - -error InvalidOwner(); -// @dev for the onlyOwner modifier -error InvalidCaller(); -error InvalidCalldata(); -error InvalidForeignChainID(); -error ObsoleteUpdate(); -error StaleUpdate(); -error UnexpectedResultLength(); -error UnexpectedResultMismatch(); - -/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. -contract QueryDemo is QueryResponse { - using BytesParsing for bytes; - - struct ChainEntry { - uint16 chainID; - address contractAddress; - uint256 counter; - uint256 blockNum; - uint256 blockTime; - } - - address private immutable owner; - uint16 private immutable myChainID; - mapping(uint16 => ChainEntry) private counters; - uint16[] private foreignChainIDs; - - bytes4 public GetMyCounter = bytes4(hex"916d5743"); - - constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { - if (_owner == address(0)) { - revert InvalidOwner(); - } - owner = _owner; - - myChainID = _myChainID; - counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); - } - - // updateRegistration should be used to add the other chains and to set / update contract addresses. - function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { - if (counters[_chainID].chainID == 0) { - foreignChainIDs.push(_chainID); - counters[_chainID].chainID = _chainID; - } - - counters[_chainID].contractAddress = _contractAddress; - } - - // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. - function getMyCounter() public view returns (uint256) { - return counters[myChainID].counter; - } - - // getState() returns this chain's view of all the counters. It is meant to be used in the front end. - function getState() public view returns (ChainEntry[] memory) { - ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); - ret[0] = counters[myChainID]; - uint256 length = foreignChainIDs.length; - - for (uint256 i = 0; i < length;) { - ret[i + 1] = counters[foreignChainIDs[i]]; - unchecked { - ++i; - } - } - - return ret; - } - - // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. - function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { - ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); - uint256 numResponses = r.responses.length; - if (numResponses != foreignChainIDs.length) { - revert UnexpectedResultLength(); - } - - for (uint256 i = 0; i < numResponses;) { - // Create a storage pointer for frequently read and updated data stored on the blockchain - ChainEntry storage chainEntry = counters[r.responses[i].chainId]; - if (chainEntry.chainID != foreignChainIDs[i]) { - revert InvalidForeignChainID(); - } - - EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); - - // Validate that update is not obsolete - validateBlockNum(eqr.blockNum, chainEntry.blockNum); - - // Validate that update is not stale - validateBlockTime(eqr.blockTime, block.timestamp - 300); - - if (eqr.result.length != 1) { - revert UnexpectedResultMismatch(); - } - - // Validate addresses and function signatures - address[] memory validAddresses = new address[](1); - bytes4[] memory validFunctionSignatures = new bytes4[](1); - validAddresses[0] = chainEntry.contractAddress; - validFunctionSignatures[0] = GetMyCounter; - - validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); - - require(eqr.result[0].result.length == 32, "result is not a uint256"); - - chainEntry.blockNum = eqr.blockNum; - chainEntry.blockTime = eqr.blockTime / 1_000_000; - chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); - - unchecked { - ++i; - } - } - - counters[myChainID].blockNum = block.number; - counters[myChainID].blockTime = block.timestamp; - counters[myChainID].counter += 1; - } - - modifier onlyOwner() { - if (owner != msg.sender) { - revert InvalidOwner(); - } - _; - } -} - ``` - -## Submit a Query Response On-Chain - -The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. - -This example submits the transaction to the demo contract: - -```jsx -const tx = await contract.updateCounters( - `0x${response.data.bytes}`, - signaturesToEvmStruct(response.data.signatures) -); -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ ---- BEGIN CONTENT --- ---- -title: Chain IDs -description: This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. -categories: Reference ---- - -# Chain IDs - -The following table documents the chain IDs used by Wormhole and places them alongside the more commonly referenced [EVM Chain IDs](https://chainlist.org/){target=\_blank}. - -!!! note - Please note, Wormhole chain IDs are different than the more commonly referenced EVM [chain IDs](https://eips.ethereum.org/EIPS/eip-155){target=\_blank}, specified in the Mainnet and Testnet ID columns. - - - - -=== "Mainnet" - - | Ethereum | 2 | 1 | -| Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | -| Acala | 12 | 787 | -| Algorand | 8 | mainnet-v1.0 | -| Aptos | 22 | 1 | -| Arbitrum | 23 | Arbitrum One-42161 | -| Avalanche | 6 | C-Chain-43114 | -| Base | 30 | Base-8453 | -| Berachain | 39 | | -| Blast | 36 | 81457 | -| BNB Smart Chain | 4 | 56 | -| Celestia | 4004 | celestia | -| Celo | 14 | 42220 | -| Cosmos Hub | 4000 | cosmoshub-4 | -| Dymension | 4007 | dymension_1100-1 | -| Evmos | 4001 | evmos_9001-2 | -| Fantom | 10 | 250 | -| Gnosis | 25 | 100 | -| HyperEVM | 47 | | -| Injective | 19 | injective-1 | -| Ink | 46 | | -| Kaia | 13 | 8217 | -| Karura | 11 | 686 | -| Kujira | 4002 | kaiyo-1 | -| Linea | 38 | 59144 | -| Mantle | 35 | 5000 | -| Mezo | 50 | | -| Monad | 48 | | -| Moonbeam | 16 | 1284 | -| NEAR | 15 | mainnet | -| Neon | 17 | 245022934 | -| Neutron | 4003 | neutron-1 | -| Noble | 4009 | noble-1 | -| Oasis | 7 | 42262 | -| Optimism | 24 | 10 | -| Osmosis | 20 | osmosis-1 | -| Polygon | 5 | 137 | -| Provenance | 4008 | pio-mainnet-1 | -| Pythnet | 26 | | -| Scroll | 34 | 534352 | -| SEDA | 4006 | | -| Sei | 32 | pacific-1 | -| Seievm | 40 | | -| SNAXchain | 43 | 2192 | -| Stargaze | 4005 | stargaze-1 | -| Sui | 21 | 35834a8a | -| Terra | 3 | columbus-5 | -| Terra 2.0 | 18 | phoenix-1 | -| Unichain | 44 | | -| World Chain | 45 | 480 | -| X Layer | 37 | 196 | -| XPLA | 28 | dimension_37-1 | - -=== "Testnet" - - | Ethereum Holesky | 10006 | Holesky-17000 | -| Ethereum Sepolia | 10002 | Sepolia-11155111 | -| Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | -| Acala | 12 | 597 | -| Algorand | 8 | testnet-v1.0 | -| Aptos | 22 | 2 | -| Arbitrum Sepolia | 10003 | Sepolia-421614 | -| Avalanche | 6 | Fuji-43113 | -| Base Sepolia | 10004 | Base Sepolia-84532 | -| Berachain | 39 | 80084 | -| Blast | 36 | 168587773 | -| BNB Smart Chain | 4 | 97 | -| Celestia | 4004 | mocha-4 | -| Celo | 14 | Alfajores-44787 | -| Cosmos Hub | 4000 | theta-testnet-001 | -| Dymension | 4007 | | -| Evmos | 4001 | evmos_9000-4 | -| Fantom | 10 | 4002 | -| Gnosis | 25 | Chiado-10200 | -| HyperEVM | 47 | 998 | -| Injective | 19 | injective-888 | -| Ink | 46 | 763373 | -| Kaia | 13 | Kairos-1001 | -| Karura | 11 | 596 | -| Kujira | 4002 | harpoon-4 | -| Linea | 38 | 59141 | -| Mantle | 35 | Sepolia-5003 | -| Mezo | 50 | 31611 | -| Monad | 48 | 10143 | -| Moonbeam | 16 | Moonbase-Alphanet-1287 | -| NEAR | 15 | testnet | -| Neon | 17 | 245022940 | -| Neutron | 4003 | pion-1 | -| Noble | 4009 | grand-1 | -| Oasis | 7 | 42261 | -| Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | -| Osmosis | 20 | osmo-test-5 | -| Polygon Amoy | 10007 | Amoy-80002 | -| Provenance | 4008 | | -| Pythnet | 26 | | -| Scroll | 34 | Sepolia-534351 | -| SEDA | 4006 | seda-1-testnet | -| Sei | 32 | atlantic-2 | -| Seievm | 40 | | -| SNAXchain | 43 | 13001 | -| Stargaze | 4005 | | -| Sui | 21 | 4c78adac | -| Terra | 3 | bombay-12 | -| Terra 2.0 | 18 | pisco-1 | -| Unichain | 44 | Unichain Sepolia-1301 | -| World Chain | 45 | 4801 | -| X Layer | 37 | 195 | -| XPLA | 28 | cube_47-5 | - ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ ---- BEGIN CONTENT --- ---- -title: Wormhole Finality | Consistency Levels -description: This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. -categories: Reference ---- - -# Wormhole Finality - -The following table documents each chain's `consistencyLevel` values (i.e., finality reached before signing). The consistency level defines how long the Guardians should wait before signing a VAA. The finalization time depends on the specific chain's consensus mechanism. The consistency level is a `u8`, so any single byte may be used. However, a small subset has particular meanings. If the `consistencyLevel` isn't one of those specific values, the `Otherwise` column describes how it's interpreted. - - - -| Ethereum | 200 | 201 | | finalized | ~ 19min | Details | -| Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | -| Algorand | | | 0 | | ~ 4s | Details | -| Aptos | | | 0 | | ~ 4s | Details | -| Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | -| Avalanche | 200 | | | finalized | ~ 2s | Details | -| Base | 200 | 201 | | finalized | ~ 18min | | -| Berachain | 200 | | | finalized | ~ 4s | | -| Blast | 200 | 201 | | finalized | ~ 18min | | -| BNB Smart Chain | 200 | 201 | | finalized | ~ 48s | Details | -| Celestia | | | 0 | | ~ 5s | | -| Celo | 200 | | | finalized | ~ 10s | | -| Cosmos Hub | | | 0 | | ~ 5s | | -| Dymension | | | 0 | | ~ 5s | | -| Evmos | | | 0 | | ~ 2s | | -| Fantom | 200 | | | finalized | ~ 5s | | -| Injective | | | 0 | | ~ 3s | | -| Ink | | | 0 | | ~ 9min | | -| Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | -| Kujira | | | 0 | | ~ 3s | | -| Mantle | 200 | 201 | | finalized | ~ 18min | | -| Mezo | | | 0 | | ~ 8s | | -| Monad | | | 0 | | ~ 2s | | -| Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | -| NEAR | | | 0 | | ~ 2s | Details | -| Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | -| Optimism | 200 | 201 | | finalized | ~ 18min | | -| Osmosis | | | 0 | | ~ 6s | | -| Polygon | 200 | | | finalized | ~ 66s | Details | -| Scroll | 200 | | | finalized | ~ 16min | | -| Sei | | | 0 | | ~ 1s | | -| Stargaze | | | 0 | | ~ 5s | | -| Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | -| Terra 2.0 | | | 0 | | ~ 6s | | -| Unichain | 200 | 201 | | finalized | ~ 18min | | -| World Chain | | | 0 | | ~ 18min | | -| X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | - ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ ---- BEGIN CONTENT --- ---- -title: Contract Addresses -description: This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. -categories: Reference ---- - -# Contract Addresses - -## Core Contracts - - - - -=== "Mainnet" - - | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | -| Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Algorand | 842125965 | -| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | -| Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | -| Avalanche | 0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c | -| Base | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Berachain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| Blast | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| BNB Smart Chain | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | -| Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | -| Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | -| NEAR | contract.wormhole_crypto.near | -| Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | -| Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | -| Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | -| Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | -| Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | -| SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | -| Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | -| Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | -| Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | -| X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | - -=== "Testnet" - - | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | -| Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | -| Algorand | 86525623 | -| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | -| Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | -| Avalanche | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | -| Base Sepolia | 0x79A1027a6A159502049F10906D333EC57E95F083 | -| Berachain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Blast | 0x473e002D7add6fB67a4964F13bFd61280Ca46886 | -| BNB Smart Chain | 0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D | -| Celo | 0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56 | -| Fantom | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | -| Gnosis | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| HyperEVM | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | -| Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | -| Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | -| Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | -| Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | -| Monad | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Moonbeam | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | -| NEAR | wormhole.wormhole.testnet | -| Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | -| Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | -| Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | -| Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | -| Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | -| Pythnet | EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z | -| Scroll | 0x055F47F1250012C6B20c436570a76e52c17Af2D5 | -| Sei | sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s | -| Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | -| Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | -| Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | -| X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | - -=== "Devnet" - - | Ethereum | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | -| Solana | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | -| Algorand | 1004 | -| Aptos | 0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017 | -| BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | -| NEAR | wormhole.test.near | -| Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | -| Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | - - -## Token Bridge - - - - -=== "Mainnet" - - | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | -| Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | -| Algorand | 842126029 | -| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | -| Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | -| Avalanche | 0x0e082F06FF657D94310cB8cE8B0D9a04541d8052 | -| Base | 0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627 | -| Berachain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| Blast | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| BNB Smart Chain | 0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7 | -| Celo | 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed | -| Fantom | 0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2 | -| Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | -| Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | -| Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | -| NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | -| Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | -| Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | -| Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | -| SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | -| Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | -| Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | -| Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | -| X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | - -=== "Testnet" - - | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | -| Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | -| Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | -| Algorand | 86525641 | -| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | -| Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Avalanche | 0x61E44E506Ca5659E6c0bba9b678586fA2d729756 | -| Base Sepolia | 0x86F55A04690fd7815A3D802bD587e83eA888B239 | -| Berachain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Blast | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | -| BNB Smart Chain | 0x9dcF9D205C9De35334D646BeE44b2D2859712A09 | -| Celo | 0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153 | -| Fantom | 0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8 | -| HyperEVM | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | -| Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | -| Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | -| Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | -| Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | -| Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| Monad | 0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659 | -| Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | -| NEAR | token.wormhole.testnet | -| Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | -| Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | -| Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | -| Sei | sei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2 | -| Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | -| SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | -| Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | -| Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | -| X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | - -=== "Devnet" - - | Ethereum | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | -| Solana | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | -| Algorand | 1006 | -| Aptos | 0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31 | -| BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | -| NEAR | token.test.near | -| Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | -| Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | - - -## Wormhole Relayer - - - - -=== "Mainnet" - - | Ethereum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Arbitrum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Avalanche | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Base | 0x706f82e9bb5b0813501714ab5974216704980e31 | -| Berachain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Blast | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| BNB Smart Chain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Celo | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Fantom | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Ink | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Kaia | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Mantle | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Moonbeam | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | -| X Layer | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | - -=== "Testnet" - - | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | - -=== "Devnet" - - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - - -## CCTP - - - - -=== "Mainnet" - - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | - -=== "Testnet" - - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | - -=== "Devnet" - - N/A - - - -## Settlement Token Router - -=== "Mainnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - -=== "Testnet" - - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | - - -## Read-Only Deployments - -=== "Mainnet" - - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | - -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/ ---- BEGIN CONTENT --- ---- -title: Reference -description: Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -categories: Reference ---- - -# Reference - -## Get Started - -In this section, you'll find reference information that is essential for development. This includes Wormhole chain IDs, canonical contract addresses, and finality levels for Guardians for each of the supported blockchains in the Wormhole ecosystem. - -
- -- :octicons-list-ordered-16:{ .lg .middle } **Chain IDs** - - --- - - Find a mapping of Wormhole chain IDs to the names and network IDs of the supported blockchains. - - [:custom-arrow: View list of chain IDs](/docs/products/reference/chain-ids/) - -- :material-timer-sand:{ .lg .middle } **Wormhole Finality** - - --- - - See the levels of finality (consistency) a transaction should meet before being signed by a Guardian for each network. - - [:custom-arrow: View list of finality levels](/docs/products/reference/consistency-levels/) - -- :octicons-file-code-16:{ .lg .middle } **Contract Addresses** - - --- - - Discover the contract addresses for Wormhole-deployed contracts on each of the supported blockchains. - - This includes the following protocol contracts: - - - Core Contract - - Token Bridge - - NFT Bridge - - Wormhole relayer - - CCTP - - [:custom-arrow: View list of contract addresses](/docs/products/reference/contract-addresses/) - -- :octicons-checkbox-16:{ .lg .middle } **Wormhole Formatted Addresses** - - --- - - Learn how Wormhole formats addresses into a 32-byte hex format for cross-chain compatibility. - - This includes converting addresses between their native formats and the Wormhole format across multiple blockchains. - - [:custom-arrow: View details on Wormhole formatted addresses](/docs/products/reference/wormhole-formatted-addresses/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- - -# Wormhole Formatted Addresses - -## Introduction - -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. - -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. - -## Platform-Specific Address Formats - -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. - -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | - -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - -### Address Format Handling - -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: - -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` - -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - -## Universal Address Methods - -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. - -Key functions: - - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format - - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` - - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` - - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform - - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` - - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations - - ```typescript - console.log(universalAddress.toString()); - ``` - -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. - -## Convert Between Native and Wormhole Formatted Addresses - -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. - -### Convert a Native Address to a Wormhole Formatted Address - -Example conversions for EVM and Solana: - -=== "EVM" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; - -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` - -=== "Solana" - - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; - -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` - -The result is a standardized address format that is ready for cross-chain operations. - -### Convert Back to Native Addresses - -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: - -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); - -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` - -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. - -## Use Cases for Wormhole Formatted Addresses - -### Cross-chain Token Transfers - -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. - -### Smart Contract Interactions - -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. - -### DApp Development - -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. - -### Relayers and Infrastructure - -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/start-building/ ---- BEGIN CONTENT --- ---- -title: Start Building -description: This section has all you need to start developing with Wormhole, including a guide to supported networks, tool sets, and code examples. ---- - -# Start Building - -Wormhole's role as a Generic Message Passing (GMP) protocol means it facilitates interoperability across multiple areas of project development. The following sections will help you locate the tools most relevant to your development needs whether you are focused on building frontend user interfaces or smart contracts and protocols. This section also links to developer resources like references and code examples which are helpful for all builders looking to integrate with Wormhole. - -## Get Hands-On - -
- -- :octicons-repo-16:{ .lg .middle } **Tutorials** - - --- - - Follow in-depth, step-by-step tutorials to learn how to build cross-chain contracts, integrate Wormhole's SDK, and more. - - [:custom-arrow: Explore tutorials](/docs/tutorials/) - -
- -## Essential Resources for Development - -
- -- :octicons-broadcast-16:{ .lg .middle } **Supported Networks** - - --- - - Explore the blockchains supported by Wormhole for cross-chain communication and asset transfers. Understand which networks are available for both Testnet and Mainnet environments. - - [:custom-arrow: Discover supported networks](/docs/products/reference/supported-networks/) - -- :octicons-goal-16:{ .lg .middle } **Testnet Faucets** - - --- - - Get Testnet tokens to start experimenting with cross-chain transfers and contract deployment. - - [:custom-arrow: Find Testnet faucets](/docs/products/reference/testnet-faucets/) - -- :octicons-list-unordered-16:{ .lg .middle } **Reference** - - --- - - Access the essential Wormhole chain IDs and smart contract addresses for messaging protocols, token bridges, and other key components. - - [:custom-arrow: Explore Reference](/docs/products/reference/){target=\_blank} - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/start-building/products/ ---- BEGIN CONTENT --- ---- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics ---- - -# Products - -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. - -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. - -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. - -## Transfer Products - -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - -- [**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods - -
- -::spantable:: - -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | - -::end-spantable:: - -
- -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. - -## Real-time Data - -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. - -## Multichain Governance - -[**MultiGov**](/docs/learn/governance/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ ---- BEGIN CONTENT --- ---- -title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. -categories: Reference ---- - -# Supported Networks - -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment - - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ ---- BEGIN CONTENT --- ---- -title: Testnet Faucets -description: This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. -categories: Reference ---- - -# Testnet Faucets - -## Get Started - -Don't let the need for testnet tokens get in the way of buildling your next great idea with Wormhole. Use this guide to quickly locate the testnet token faucets you need to deploy and test applications and contracts on Wormhole's supported networks. - - - -
- -### EVM - -| Ethereum Holesky | EVM | ETH | Alchemy Faucet | -| Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | -| Arbitrum Sepolia | EVM | ETH | List of Faucets | -| Avalanche | EVM | AVAX | Official Avalanche Faucet | -| Base Sepolia | EVM | ETH | List of Faucets | -| Berachain | EVM | BERA | Official Berachain Faucet | -| Blast | EVM | ETH | List of Faucets | -| BNB Smart Chain | EVM | BNB | Official BNB Faucet | -| Celo | EVM | CELO | Official Celo Faucet | -| Fantom | EVM | FTM | Official Fantom Faucet | -| Gnosis | EVM | xDAI | Official Gnosis Faucet | -| HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | -| Ink | EVM | ETH | Official Ink Faucet | -| Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | -| Linea | EVM | ETH | List of Faucets | -| Mantle | EVM | MNT | Official Mantle Faucet | -| Monad | EVM | MON | Official Monad Faucet | -| Moonbeam | EVM | DEV | Official Moonbeam Faucet | -| Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | -| Optimism Sepolia | EVM | ETH | Superchain Faucet | -| Polygon Amoy | EVM | POL | Official Polygon Faucet | -| Scroll | EVM | ETH | List of Faucets | -| Unichain | EVM | ETH | QuickNode Faucet | -| World Chain | EVM | ETH | Alchemy Faucet | -| X Layer | EVM | OKB | X Layer Official Faucet | - -### SVM - -| Pythnet | SVM | ETH | Superchain Faucet | - -### AVM - -| Algorand | AVM | ALGO | Official Algorand Faucet | - -### CosmWasm - -| Celestia | CosmWasm | TIA | Discord Faucet | -| Cosmos Hub | CosmWasm | ATOM | Discord Faucet | -| Evmos | CosmWasm | TEVMOS | Official Evmos Faucet | -| Injective | CosmWasm | INJ | Official Injective Faucet | -| Kujira | CosmWasm | KUJI | Discord Faucet | -| Neutron | CosmWasm | NTRN | List of Faucets | -| Noble | CosmWasm | USDC | Circle Faucet | -| Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | -| SEDA | CosmWasm | SEDA | Official SEDA Faucet | -| Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | -| Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | - -### Move VM - -| Aptos | Move VM | APT | Official Aptos Faucet | - -### NEAR VM - -| NEAR | NEAR VM | NEAR | Official NEAR Faucet | - -### Sui Move VM - -| Sui | Sui Move VM | SUI | List of Faucets | -
- ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
-
- -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
-
- -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
-
- - -
-
- -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
-
- - -
-
- -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
-
- - -
-
- -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
-
- -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
-
- -
-
- -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
-
- - -
-
- -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
-
- -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
-
- - -
-
- -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
-
- - -
-
- -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
-
- - -
-
- -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
-
- - -
-
- -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
-
- - -
-
- -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
-
- -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/build/transfers/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
-
- - -
-
- -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
-
- - -
-
- -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/build/transfers/native-token-transfers/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
-
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/toolkit/cli/ ---- BEGIN CONTENT --- ---- -title: Wormhole CLI -description: Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. -categories: Solidity-SDK, Typescript-SDK ---- - -# Wormhole CLI - -This tool is a command-line interface to Wormhole, allowing you to perform various actions, such as querying a transaction's status or submitting token transfers. - -## Installation - -Clone the repository and change directories to the appropriate directory: - -```bash -git clone https://github.com/wormhole-foundation/wormhole && -cd wormhole/clients/js -``` - -Build and install the CLI tool: - -```bash -make install -``` - -This installs two binaries, `worm-fetch-governance` and `worm` on your `$PATH`. To use `worm`, set up `$HOME/.wormhole/.env` with your private keys, based on `.env.sample` in this folder. - -## Usage - -You can interact with the Wormhole CLI by typing `worm` and including the `command` and any necessary subcommands and parameters. - -| Command | Description | -|--------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| -| `worm aptos INSERT_COMMAND` | Aptos utilities | -| `worm edit-vaa INSERT_COMMAND` | Edits or generates a VAA | -| `worm evm INSERT_COMMAND` | EVM utilities | -| `worm generate INSERT_COMMAND` | Generate VAAs (Devnet and Testnet only) | -| `worm info INSERT_COMMAND` | Contract, chain, RPC, and address information utilities | -| `worm near INSERT_NETWORK, INSERT_ACCOUNT` | NEAR utilities | -| `worm parse INSERT_VAA` | Parse a VAA (can be in either hex or base64 format) | -| `worm recover INSERT_DIGEST INSERT_SIGNATURE` | Recover an address from a signature | -| `worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH` | Prints information about the automatic delivery initiated on the specified network, chain, and transaction hash | -| `worm submit INSERT_VAA` | Execute a VAA | -| `worm sui INSERT_COMMAND` | Sui utilities | -| `worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK` | Transfers a token | -| `worm verify-vaa INSERT_VAA, INSERT_NETWORK` | Verifies a VAA by querying the Core Contract on Ethereum | - -You can also refer to the below options, available with all `worm` commands: - -```bash -Options: - --help Show help [boolean] - --version Show version number [boolean] -``` - -### Subcommands - -??? code "Aptos" - ```bash - worm aptos INSERT_COMMAND - -Commands: - worm aptos init-token-bridge Init token bridge contract - worm aptos init-wormhole Init Wormhole core contract - worm aptos deploy Deploy an Aptos package - worm aptos deploy-resource Deploy an Aptos package using a - resource account - worm aptos send-example-message Send example message - - worm aptos derive-resource-account Derive resource account address - - worm aptos derive-wrapped-address Derive wrapped coin type - - worm aptos hash-contracts Hash contract bytecodes for upgrade - worm aptos upgrade Perform upgrade after VAA has been - submitted - worm aptos migrate Perform migration after contract - upgrade - worm aptos faucet Request money from the faucet for a - given account - worm aptos start-validator Start a local aptos validator - -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` - -??? code "Edit VAA" - ```bash - worm edit-vaa INSERT_COMMAND - -Options: - --help Show help [boolean] - --version Show version number [boolean] - -v, --vaa vaa in hex format [string] [required] - -n, --network Network - [required] [choices: "mainnet", "testnet", "devnet"] - --guardian-set-index, --gsi guardian set index [number] - --signatures, --sigs comma separated list of signatures [string] - --wormscanurl, --wsu url to wormscan entry for the vaa that - includes signatures [string] - --wormscan, --ws if specified, will query the wormscan entry - for the vaa to get the signatures [boolean] - --emitter-chain-id, --ec emitter chain id to be used in the vaa - [number] - --emitter-address, --ea emitter address to be used in the vaa[string] - --nonce, --no nonce to be used in the vaa [number] - --sequence, --seq sequence number to be used in the vaa[string] - --consistency-level, --cl consistency level to be used in the vaa - [number] - --timestamp, --ts timestamp to be used in the vaa in unix - seconds [number] - -p, --payload payload in hex format [string] - --guardian-secret, --gs Guardian's secret key [string] - ``` - -??? code "EVM" - ```bash - worm evm INSERT_COMMAND - -Commands: - worm evm address-from-secret Compute a 20 byte eth address from a 32 - byte private key - worm evm storage-update Update a storage slot on an EVM fork - during testing (anvil or hardhat) - worm evm chains Return all EVM chains - worm evm info Query info about the on-chain state of - the contract - worm evm hijack Override the guardian set of the core - bridge contract during testing (anvil - or hardhat) - worm evm start-validator Start a local EVM validator - -Options: - --help Show help [boolean] - --version Show version number [boolean] - --rpc RPC endpoint [string] - ``` - -??? code "Generate" - ```bash - worm generate INSERT_COMMAND - -Commands: - worm generate registration Generate registration VAA - worm generate upgrade Generate contract upgrade VAA - worm generate attestation Generate a token attestation VAA - worm generate recover-chain-id Generate a recover chain ID VAA - worm generate Sets the default delivery provider - set-default-delivery-provider for the Wormhole Relayer contract - -Options: - --help Show help [boolean] - --version Show version number [boolean] - -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] - ``` - -??? code "Info" - ```bash - worm info INSERT_COMMAND - -Commands: - worm info chain-id Print the wormhole chain ID integer - associated with the specified chain - name - worm info contract Print contract address - - worm info emitter
Print address in emitter address - format - worm info origin
Print the origin chain and address - of the asset that corresponds to the - given chain and address. - worm info registrations Print chain registrations - - worm info rpc Print RPC address - worm info wrapped Print the wrapped address on the - target chain that corresponds with - the specified origin chain and - address. - -Options: - --help Show help [boolean] - --version Show version number [boolean]
- ``` - -??? code "NEAR" - ```bash - worm near INSERT_COMMAND - -Commands: - worm near contract-update Submit a contract update using our specific - APIs - worm near deploy Submit a contract update using near APIs - -Options: - --help Show help [boolean] - --version Show version number [boolean] - -m, --module Module to query [choices: "Core", "NFTBridge", "TokenBridge"] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - --account Near deployment account [string] [required] - --attach Attach some near [string] - --target Near account to upgrade [string] - --mnemonic Near private keys [string] - --key Near private key [string] - -r, --rpc Override default rpc endpoint url [string] - ``` - -??? code "Parse" - ```bash - worm parse INSERT_VAA - -Positionals: - vaa vaa [string] - -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` - -??? code "Recover" - ```bash - worm recover INSERT_DIGEST INSERT_SIGNATURE - -Positionals: - digest digest [string] - signature signature [string] - -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` - -??? code "Status" - ```bash - worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH - -Positionals: - network Network [choices: - 'mainnet', - 'testnet', - 'devnet'] - chain Source chain - [choices: - 'unset', - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - tx Source transaction hash [string] - -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` - -??? code "Submit" - ```bash - worm submit INSERT_VAA - -Positionals: - vaa vaa [string] - -Options: - --help Show help [boolean] - --version Show version number [boolean] - -c, --chain chain name -[choices: 'unset', - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - -n, --network Network - [required] - [choices: - 'mainnet', - 'testnet', - 'devnet'] - -a, --contract-address Contract to submit VAA to (override config) [string] - --rpc RPC endpoint [string] - --all-chains, --ac Submit the VAA to all chains except for the origin - chain specified in the payload - [boolean] [default: false] - ``` - -??? code "Sui" - ```bash - worm sui INSERT_COMMAND - -Commands: - worm sui build-coin Build wrapped coin and dump bytecode. - - Example: - worm sui build-coin -d 8 -v V__0_1_1 -n - testnet -r - "https://fullnode.testnet.sui.io:443" - worm sui deploy Deploy a Sui package - worm sui init-example-message-app Initialize example core message app - worm sui init-token-bridge Initialize token bridge contract - worm sui init-wormhole Initialize wormhole core contract - worm sui publish-example-message Publish message from example app via - core bridge - worm sui setup-devnet Setup devnet by deploying and - initializing core and token bridges and - submitting chain registrations. - worm sui objects Get owned objects by owner - worm sui package-id Get package ID from State object ID - worm sui tx Get transaction details - -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` - -??? code "Transfer" - ```bash - worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK - -Options: - --help Show help [boolean] - --version Show version number [boolean] - --src-chain source chain [required] [choices: - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - --dst-chain destination chain - [required] [choices: - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - --dst-addr destination address [string] [required] - --token-addr token address [string] [default: native token] - --amount token amount [string] [required] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - --rpc RPC endpoint [string] - ``` - -??? code "Verify VAA" - ```bash - worm verify-vaa INSERT_VAA, INSERT_NETWORK - -Options: - --help Show help [boolean] - --version Show version number [boolean] - -v, --vaa vaa in hex format [string] [required] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - ``` - - -## Examples - -### VAA generation - -Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: - -```bash -worm generate registration --module NFTBridge \ - --chain bsc \ - --contract-address 0x706abc4E45D419950511e474C7B9Ed348A4a716c \ - --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 -``` - -The below example generates a token attestation VAA: - -```bash -worm generate attestation --emitter-chain ethereum \ - --emitter-address 11111111111111111111111111111115 \ - --chain ethereum \ - --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ - --decimals 6 \ - --symbol USDC \ - --name USDC \ - --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 -``` - -### VAA parsing - -Use `parse` to parse a VAA into JSON: - -```bash -worm parse $(worm-fetch-governance 13940208096455381020) -``` - -This example will fetch governance VAA `13940208096455381020` and print it as JSON: - -```bash -# ...signatures elided -timestamp: 1651416474, -nonce: 1570649151, -emitterChain: 1, -emitterAddress: '0000000000000000000000000000000000000000000000000000000000000004', -sequence: 13940208096455381020n, -consistencyLevel: 32, -payload: { - module: 'Core', - type: 'GuardianSetUpgrade', - chain: 0, - newGuardianSetIndex: 2, - newGuardianSetLength: 19, - newGuardianSet: [ - '58cc3ae5c097b213ce3c81979e1b9f9570746aa5', - 'ff6cb952589bde862c25ef4392132fb9d4a42157', - '114de8460193bdf3a2fcf81f86a09765f4762fd1', - '107a0086b32d7a0977926a205131d8731d39cbeb', - '8c82b2fd82faed2711d59af0f2499d16e726f6b2', - '11b39756c042441be6d8650b69b54ebe715e2343', - '54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd', - '66b9590e1c41e0b226937bf9217d1d67fd4e91f5', - '74a3bf913953d695260d88bc1aa25a4eee363ef0', - '000ac0076727b35fbea2dac28fee5ccb0fea768e', - 'af45ced136b9d9e24903464ae889f5c8a723fc14', - 'f93124b7c738843cbb89e864c862c38cddcccf95', - 'd2cc37a4dc036a8d232b48f62cdd4731412f4890', - 'da798f6896a3331f64b48c12d1d57fd9cbe70811', - '71aa1be1d36cafe3867910f99c09e347899c19c3', - '8192b6e7387ccd768277c17dab1b7a5027c0b3cf', - '178e21ad2e77ae06711549cfbb1f9c7a9d8096e8', - '5e1487f35515d02a92753504a8d75471b9f49edb', - '6fbebc898f403e4773e95feb15e80c9a99c8348d' - ] -} -``` - -### Submitting VAAs - -Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): - -```bash -worm submit $(cat my-nft-registration.txt) --network mainnet -``` - -The script will ask you to specify the target chain for VAAs that don't have a specific target chain (like registrations or Guardian set upgrades). For example, to submit a Guardian set upgrade on all chains, simply run: - -```bash -worm-fetch-governance 13940208096455381020 > guardian-upgrade.txt -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain oasis -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain aurora -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain fantom -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain karura -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain acala -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain klaytn -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain avalanche -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain polygon -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain bsc -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain solana -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain terra -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain ethereum -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain celo -``` - -The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. - -### Getting Info - -To get info about a contract (only EVM supported at this time), use the following command: - -```bash -worm evm info -c bsc -n mainnet -m TokenBridge -``` - -Running this command generates the following output: - -```bash -{ - "address": "0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "wormhole": "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B", - "implementation": "0x621199f6beB2ba6fbD962E8A52A320EA4F6D4aA3", - "isInitialized": true, - "tokenImplementation": "0x7f8C5e730121657E17E452c5a1bA3fA1eF96f22a", - "chainId": 4, - "finality": 15, - "evmChainId": "56", - "isFork": false, - "governanceChainId": 1, - "governanceContract": "0x0000000000000000000000000000000000000000000000000000000000000004", - "WETH": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", - "registrations": { - "Solana": "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5", - "Ethereum": "0x0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585", - "Terra": "0x0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2", - "Polygon": "0x0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde", - "Avalanche": "0x0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052", - "Oasis": "0x0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564", - "Algorand": "0x67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45", - "Aurora": "0x00000000000000000000000051b5123a7b0f9b2ba265f9c4c8de7d78d52f510f", - "Fantom": "0x0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2", - "Karura": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", - "Acala": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", - "Klaytn": "0x0000000000000000000000005b08ac39eaed75c0439fc750d9fe7e1f9dd0193f", - "Celo": "0x000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed", - "Near": "0x148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7", - "Moonbeam": "0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92", - "Neon": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Terra2": "0xa463ad028fb79679cfc8ce1efba35ac0e77b35080a1abe9bebe83461f176b0a3", - "Injective": "0x00000000000000000000000045dbea4617971d93188eda21530bc6503d153313", - "Osmosis": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Sui": "0xccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5", - "Aptos": "0x0000000000000000000000000000000000000000000000000000000000000001", - "Arbitrum": "0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c", - "Optimism": "0x0000000000000000000000001d68124e65fafc907325e3edbf8c4d84499daa8b", - "Gnosis": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Pythnet": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Xpla": "0x8f9cf727175353b17a5f574270e370776123d90fd74956ae4277962b4fdee24c", - "Btc": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Base": "0x0000000000000000000000008d2de8d2f73f1f4cab472ac9a881c9b123c79627", - "Sei": "0x86c5fd957e2db8389553e1728f9c27964b22a8154091ccba54d75f4b10c61f5e", - "Rootstock": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Scroll": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Mantle": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Blast": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Xlayer": "0x0000000000000000000000005537857664b0f9efe38c9f320f75fef23234d904", - "Linea": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Berachain": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Seievm": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Snaxchain": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Wormchain": "0xaeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924", - "Cosmoshub": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Evmos": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Kujira": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Neutron": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Celestia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Stargaze": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Seda": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Dymension": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Provenance": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "ArbitrumSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "BaseSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "OptimismSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Holesky": "0x0000000000000000000000000000000000000000000000000000000000000000", - "PolygonSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000" - } -} -``` - -### Additional Info Examples - -You can get the contract address for a module as follows: - -```bash -worm info rpc INSERT_NETWORK INSERT_CHAIN INSERT_MODULE -``` - -To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can provide the following command: - -```bash -worm info contract mainnet bsc NFTBridge -``` - -You can get the RPC address for a chain as follows: - -```bash -worm info rpc INSERT_NETWORK INSERT_CHAIN -``` - -To get the RPC address for BSC Mainnet, for example, you can provide the following command: - -```bash -worm info rpc mainnet bsc -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/toolkit/dev-env/ ---- BEGIN CONTENT --- ---- -title: Local Dev Environment -description: Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. -categories: Solidity-SDK, Typescript-SDK ---- - -# Development Environment - -Developers building for smart contract integration will want to set up a development environment to allow testing the full integration, possibly including VAA generation and relaying. - -## Tooling Installation - -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. - -## Development Stages - -Different approaches to development and testing are recommended at various stages of application development. - -### Initial Development - -During the initial development of an on-chain application, the best option is to use the native tools available in the environment. You can visit the following resources for more information: - -- **[Environment](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - select the folder for the desired network to learn about the recommended native toolset -- **[Mock Guardian](https://github.com/wormhole-foundation/wormhole/blob/main/sdk/js/src/mock/wormhole.ts){target=\_blank}** - it's recommended to set up a mock Guardian or Emitter to provide signed VAAsFor any program methods that require some message be sent or received. -- **[Wormhole Scaffolding repository](https://github.com/wormhole-foundation/wormhole-scaffolding/blob/main/evm/ts-test/01_hello_world.ts){target=\_blank}** - example mock Guardian test - -Relying on native tools when possible allows for more rapid prototyping and iteration. - -### Integration - -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. - -!!! note - Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. - -### Prepare for Deployment - -Once you've finished the application's initial development and performed integration testing, you should set up a CI test environment. The best option for that is likely to be [Tilt](https://tilt.dev/){target=\_blank} since it allows you to spin up any chains supported by Wormhole in a consistent environment. - -## Validator Setup with Tilt - -### Tilt -If you'd like to set up a local validator environment, follow the setup guide for Tilt. Tilt is a full-fledged Kubernetes deployment of every chain connected to Wormhole, along with a Guardian node. It usually takes 30 minutes to spin up fully, but it comes with all chains running out of the box. Refer to the [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} page for a complete guide to setting up and configuring Tilt. - -## Deploying to Public Networks - -### Testnet - -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: - -```text -https://api.testnet.wormholescan.io -``` - -### Mainnet - -The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: - -```text -https://api.wormholescan.io -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/toolkit/faqs/ ---- BEGIN CONTENT --- ---- -title: Toolkit FAQs -description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. -categories: Solidity-SDK, Typescript-SDK ---- - -# Toolkit FAQs - -## Why does the `toNative` function in the TypeScript SDK return an error? - -The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. - -To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: - -```typescript -import solana from '@wormhole-foundation/sdk/solana'; -const wh = await wormhole('Testnet', [solana]); -``` - -## How can I retrieve the history of previously bridged transactions? - -To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: - -```bash -https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS -``` - -Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. - -???- example "Fetch transaction history for a specific address" - ```bash - curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" +Options: + --help Show help [boolean] + --version Show version number [boolean] + -c, --chain chain name +[choices: 'unset', + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + -n, --network Network + [required] + [choices: + 'mainnet', + 'testnet', + 'devnet'] + -a, --contract-address Contract to submit VAA to (override config) [string] + --rpc RPC endpoint [string] + --all-chains, --ac Submit the VAA to all chains except for the origin + chain specified in the payload + [boolean] [default: false] ``` -## How can I manually submit a VAA to a destination chain in the correct format? - -To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: - -1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format - +??? code "Sui" ```bash - https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced - ``` - -2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python - -3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - - - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field - -Following these steps, you can manually submit a VAA in the proper format to a destination chain. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/toolkit/ ---- BEGIN CONTENT --- ---- -title: Wormhole Tooling -description: This page lists key dev tools, including the WormholeScan Explorer, Wormhole CLI, Wormhole SDKs, and APIs for querying network data. -categories: Solidity-SDK ---- - -# Wormhole Tooling - -Regardless of which network development environment you are using, there are a few Wormhole-specific tools you should know about. - -## Get Started - -
- -- :octicons-telescope-16:{ .lg .middle } **Wormholescan** - - --- + worm sui INSERT_COMMAND - Wormholescan is an explorer for looking at individual transfer statuses on Mainnet and Testnet. +Commands: + worm sui build-coin Build wrapped coin and dump bytecode. - [:custom-arrow: Review transactions on Wormholescan](https://wormholescan.io){target=\_blank} + Example: + worm sui build-coin -d 8 -v V__0_1_1 -n + testnet -r + "https://fullnode.testnet.sui.io:443" + worm sui deploy Deploy a Sui package + worm sui init-example-message-app Initialize example core message app + worm sui init-token-bridge Initialize token bridge contract + worm sui init-wormhole Initialize wormhole core contract + worm sui publish-example-message Publish message from example app via + core bridge + worm sui setup-devnet Setup devnet by deploying and + initializing core and token bridges and + submitting chain registrations. + worm sui objects Get owned objects by owner + worm sui package-id Get package ID from State object ID + worm sui tx Get transaction details -- :octicons-plug-16:{ .lg .middle } **Wormholescan API** +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` - --- +??? code "Transfer" + ```bash + worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK - Leverage the Wormholescan API to programmatically access Wormhole network data, including transaction details and VAAs. +Options: + --help Show help [boolean] + --version Show version number [boolean] + --src-chain source chain [required] [choices: + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + --dst-chain destination chain + [required] [choices: + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + --dst-addr destination address [string] [required] + --token-addr token address [string] [default: native token] + --amount token amount [string] [required] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + --rpc RPC endpoint [string] + ``` - [:custom-arrow: Explore the Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} +??? code "Verify VAA" + ```bash + worm verify-vaa INSERT_VAA, INSERT_NETWORK -- :octicons-code-square-16:{ .lg .middle } **Wormhole CLI Tool** +Options: + --help Show help [boolean] + --version Show version number [boolean] + -v, --vaa vaa in hex format [string] [required] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + ``` - --- - The Wormhole CLI is a Swiss-Army knife utility command line tool. It is excellent for creating one-off VAAs, parsing VAAs, reading Wormhole contract configurations, and more. +## Examples - [:custom-arrow: Get started with the CLI](/docs/build/toolkit/cli/) +### VAA generation -- :octicons-code-square-16:{ .lg .middle } **Wormhole SDK** +Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: - --- +```bash +worm generate registration --module NFTBridge \ + --chain bsc \ + --contract-address 0x706abc4E45D419950511e474C7B9Ed348A4a716c \ + --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 +``` - Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC transfers. +The below example generates a token attestation VAA: - [:custom-arrow: Get started with the SDK](/docs/tools/typescript-sdk/get-started/) +```bash +worm generate attestation --emitter-chain ethereum \ + --emitter-address 11111111111111111111111111111115 \ + --chain ethereum \ + --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ + --decimals 6 \ + --symbol USDC \ + --name USDC \ + --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 +``` -- :octicons-code-square-16:{ .lg .middle } **Solidity SDK** +### VAA parsing - --- +Use `parse` to parse a VAA into JSON: - Learn about Wormhole's Solidity SDK, including key components, interfaces, and tools for developing cross-chain decentralized applications on EVM-compatible blockchains. +```bash +worm parse $(worm-fetch-governance 13940208096455381020) +``` - [:custom-arrow: Get started with the SDK](/docs/tools/solidity-sdk/sdk-reference/) +This example will fetch governance VAA `13940208096455381020` and print it as JSON: -- :octicons-beaker-16:{ .lg .middle } **Tilt** +```bash +# ...signatures elided +timestamp: 1651416474, +nonce: 1570649151, +emitterChain: 1, +emitterAddress: '0000000000000000000000000000000000000000000000000000000000000004', +sequence: 13940208096455381020n, +consistencyLevel: 32, +payload: { + module: 'Core', + type: 'GuardianSetUpgrade', + chain: 0, + newGuardianSetIndex: 2, + newGuardianSetLength: 19, + newGuardianSet: [ + '58cc3ae5c097b213ce3c81979e1b9f9570746aa5', + 'ff6cb952589bde862c25ef4392132fb9d4a42157', + '114de8460193bdf3a2fcf81f86a09765f4762fd1', + '107a0086b32d7a0977926a205131d8731d39cbeb', + '8c82b2fd82faed2711d59af0f2499d16e726f6b2', + '11b39756c042441be6d8650b69b54ebe715e2343', + '54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd', + '66b9590e1c41e0b226937bf9217d1d67fd4e91f5', + '74a3bf913953d695260d88bc1aa25a4eee363ef0', + '000ac0076727b35fbea2dac28fee5ccb0fea768e', + 'af45ced136b9d9e24903464ae889f5c8a723fc14', + 'f93124b7c738843cbb89e864c862c38cddcccf95', + 'd2cc37a4dc036a8d232b48f62cdd4731412f4890', + 'da798f6896a3331f64b48c12d1d57fd9cbe70811', + '71aa1be1d36cafe3867910f99c09e347899c19c3', + '8192b6e7387ccd768277c17dab1b7a5027c0b3cf', + '178e21ad2e77ae06711549cfbb1f9c7a9d8096e8', + '5e1487f35515d02a92753504a8d75471b9f49edb', + '6fbebc898f403e4773e95feb15e80c9a99c8348d' + ] +} +``` - --- +### Submitting VAAs - Learn about Tilt, a Wormhole developer environment with a local Kubernetes set up for cross-chain testing with Guardian nodes and relayers for seamless development. +Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): - [:custom-arrow: Get started with Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} +```bash +worm submit $(cat my-nft-registration.txt) --network mainnet +``` - +To get info about a contract (only EVM supported at this time), use the following command: -
+```bash +worm evm info -c bsc -n mainnet -m TokenBridge +``` -## Additional Resources +Running this command generates the following output: -
+```bash +{ + "address": "0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", + "wormhole": "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B", + "implementation": "0x621199f6beB2ba6fbD962E8A52A320EA4F6D4aA3", + "isInitialized": true, + "tokenImplementation": "0x7f8C5e730121657E17E452c5a1bA3fA1eF96f22a", + "chainId": 4, + "finality": 15, + "evmChainId": "56", + "isFork": false, + "governanceChainId": 1, + "governanceContract": "0x0000000000000000000000000000000000000000000000000000000000000004", + "WETH": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "registrations": { + "Solana": "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5", + "Ethereum": "0x0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585", + "Terra": "0x0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2", + "Polygon": "0x0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde", + "Avalanche": "0x0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052", + "Oasis": "0x0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564", + "Algorand": "0x67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45", + "Aurora": "0x00000000000000000000000051b5123a7b0f9b2ba265f9c4c8de7d78d52f510f", + "Fantom": "0x0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2", + "Karura": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", + "Acala": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", + "Klaytn": "0x0000000000000000000000005b08ac39eaed75c0439fc750d9fe7e1f9dd0193f", + "Celo": "0x000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed", + "Near": "0x148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7", + "Moonbeam": "0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92", + "Neon": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Terra2": "0xa463ad028fb79679cfc8ce1efba35ac0e77b35080a1abe9bebe83461f176b0a3", + "Injective": "0x00000000000000000000000045dbea4617971d93188eda21530bc6503d153313", + "Osmosis": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Sui": "0xccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5", + "Aptos": "0x0000000000000000000000000000000000000000000000000000000000000001", + "Arbitrum": "0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c", + "Optimism": "0x0000000000000000000000001d68124e65fafc907325e3edbf8c4d84499daa8b", + "Gnosis": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Pythnet": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Xpla": "0x8f9cf727175353b17a5f574270e370776123d90fd74956ae4277962b4fdee24c", + "Btc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Base": "0x0000000000000000000000008d2de8d2f73f1f4cab472ac9a881c9b123c79627", + "Sei": "0x86c5fd957e2db8389553e1728f9c27964b22a8154091ccba54d75f4b10c61f5e", + "Rootstock": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Scroll": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Mantle": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Blast": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Xlayer": "0x0000000000000000000000005537857664b0f9efe38c9f320f75fef23234d904", + "Linea": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Berachain": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Seievm": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Snaxchain": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Wormchain": "0xaeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924", + "Cosmoshub": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Evmos": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Kujira": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Neutron": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Celestia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Stargaze": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Seda": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Dymension": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Provenance": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "ArbitrumSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "BaseSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "OptimismSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Holesky": "0x0000000000000000000000000000000000000000000000000000000000000000", + "PolygonSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000" + } +} +``` -- :octicons-code-square-16:{ .lg .middle } **Wormhole Spy SDK** +### Additional Info Examples - --- +You can get the contract address for a module as follows: - The Wormhole Spy SDK allows you to listen to all the Guardian Network activity. +```bash +worm info rpc INSERT_NETWORK INSERT_CHAIN INSERT_MODULE +``` - [:custom-arrow: Check out the Spy SDK repository](https://github.com/wormhole-foundation/wormhole/tree/main/spydk/js){target=\_blank} +To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can provide the following command: -- :octicons-pencil-16:{ .lg .middle } **VAA Parser** +```bash +worm info contract mainnet bsc NFTBridge +``` - --- +You can get the RPC address for a chain as follows: - The VAA Parser is a resource for parsing out details of an encoded VAA. +```bash +worm info rpc INSERT_NETWORK INSERT_CHAIN +``` - [:custom-arrow: Try the VAA Parser](https://wormholescan.io/#/developers/vaa-parser){target=\_blank} +To get the RPC address for BSC Mainnet, for example, you can provide the following command: -
+```bash +worm info rpc mainnet bsc +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ +Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ --- BEGIN CONTENT --- --- -title: Solidity SDK -description: How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. -categories: Solidity-SDK +title: Local Dev Environment +description: Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. +categories: Solidity-SDK, Typescript-SDK --- -# Solidity SDK - -## Introduction - -The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains. - -By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides: - - - **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure - - **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain - - **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement - - **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments - -These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains. - -This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing. - -## Installation - -To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project: - -```bash -forge install wormhole-foundation/wormhole-solidity-sdk@v0.1.0 -``` - -When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file: - -```toml -evm_version = "paris" -``` - -This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades. - -## Key Considerations - -Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind: - - - **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes - - **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries - - **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments - -## Concepts and Components - -The Wormhole Solidity SDK consists of key components that streamline cross-chain communication, allowing developers to securely and efficiently interact with Wormhole’s infrastructure. Below are the critical concepts and contracts you'll encounter when working with the SDK. - -### Cross-Chain Messaging with the Wormhole Relayer SDK - -The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication. - -You can refer to the [Wormhole relayer documentation](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} for more details. +# Development Environment -Key modules in the SDK include: +Developers building for smart contract integration will want to set up a development environment to allow testing the full integration, possibly including VAA generation and relaying. - - **`Base.sol`** - the core module for cross-chain messaging. It provides utility functions like `onlyWormholeRelayer()` and `setRegisteredSender()`, ensuring that only messages from trusted relayers are processed +## Tooling Installation - - **`TokenBase.sol`** - this module extends the base messaging functionality to support cross-chain token transfers. It includes utilities for securely sending and receiving tokens between EVM-compatible chains +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. - - **`CCTPBase.sol`** - designed for Circle’s Cross-Chain Transfer Protocol, this module manages asset transfers such as USDC between chains. It includes functionalities for both sending and receiving CCTP-based assets +## Development Stages - - **`CCTPAndTokenBase.sol`** - a combined module that supports token and CCTP-based asset transfers in a single implementation. This module simplifies development for applications needing to handle both types of transfers +Different approaches to development and testing are recommended at various stages of application development. -The Wormhole Solidity SDK offers a unified framework for cross-chain communication. Developers can select specific modules based on their application’s requirements, whether for messaging, token transfers, or CCTP. Each module includes built-in security measures, ensuring that only authorized senders or relayers are accepted, thereby protecting the application from unauthorized interactions. +### Initial Development -Please refer to the complete `WormholeRelayerSDK.sol` file below for further details. +During the initial development of an on-chain application, the best option is to use the native tools available in the environment. You can visit the following resources for more information: -???- code "`WormholeRelayerSDK.sol`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; +- **[Environment](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - select the folder for the desired network to learn about the recommended native toolset +- **[Mock Guardian](https://github.com/wormhole-foundation/wormhole/blob/main/sdk/js/src/mock/wormhole.ts){target=\_blank}** - it's recommended to set up a mock Guardian or Emitter to provide signed VAAsFor any program methods that require some message be sent or received. +- **[Wormhole Scaffolding repository](https://github.com/wormhole-foundation/wormhole-scaffolding/blob/main/evm/ts-test/01_hello_world.ts){target=\_blank}** - example mock Guardian test -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/constants/Chains.sol"; -import "wormhole-sdk/Utils.sol"; +Relying on native tools when possible allows for more rapid prototyping and iteration. -import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; -import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; -import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; -import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; - ``` +### Integration -### Base Contract Overview +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. -The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/Base.sol){target=\_blank} contract is a core part of the Wormhole Solidity SDK, providing essential helper functions and modifiers for managing cross-chain messages securely via the Wormhole Relayer. It handles sender registration and message validation, ensuring only authorized senders from specific chains can send messages. +!!! note + Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. - - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions +### Prepare for Deployment - ```solidity - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } - ``` +Once you've finished the application's initial development and performed integration testing, you should set up a CI test environment. The best option for that is likely to be [Tilt](https://tilt.dev/){target=\_blank} since it allows you to spin up any chains supported by Wormhole in a consistent environment. - - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources +## Validator Setup with Tilt - ```solidity - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } - ``` +### Tilt +If you'd like to set up a local validator environment, follow the setup guide for Tilt. Tilt is a full-fledged Kubernetes deployment of every chain connected to Wormhole, along with a Guardian node. It usually takes 30 minutes to spin up fully, but it comes with all chains running out of the box. Refer to the [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} page for a complete guide to setting up and configuring Tilt. -These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. +## Deploying to Public Networks -???- code "`Base.sol`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; +### Testnet -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/Utils.sol"; +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: -abstract contract Base { - IWormholeRelayer public immutable wormholeRelayer; - IWormhole public immutable wormhole; +```text +https://api.testnet.wormholescan.io +``` - address registrationOwner; - mapping(uint16 => bytes32) registeredSenders; +### Mainnet - constructor(address _wormholeRelayer, address _wormhole) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - wormhole = IWormhole(_wormhole); - registrationOwner = msg.sender; - } +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: - modifier onlyWormholeRelayer() { - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } +```text +https://api.wormholescan.io +``` +--- END CONTENT --- - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } +Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ +--- BEGIN CONTENT --- +--- +title: Toolkit FAQs +description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. +categories: Solidity-SDK, Typescript-SDK +--- - /** - * Sets the registered address for 'sourceChain' to 'sourceAddress' - * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid - * - * Assumes only one sender per chain is valid - * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) - */ - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -} - ``` +# Toolkit FAQs -### Interface for Cross-Chain Messages +## Why does the `toNative` function in the TypeScript SDK return an error? -The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. +The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. -For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: +To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: - - **`IWormholeRelayer`** – methods for sending cross-chain messages, VAAs, and token transfers - - **`IWormholeReceiver`** – the required implementation for receiving cross-chain messages - - **`quoteEVMDeliveryPrice()`** – how to estimate gas and fees for cross-chain transactions +```typescript +import solana from '@wormhole-foundation/sdk/solana'; +const wh = await wormhole('Testnet', [solana]); +``` -These interfaces reduce the complexity of cross-chain dApp development by abstracting away the details of relayer infrastructure, ensuring that message delivery is handled efficiently. +## How can I retrieve the history of previously bridged transactions? -### Advanced Concepts +To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: -For developers interested in exploring additional advanced topics, the following sections provide insights into key aspects of the SDK’s functionality. +```bash +https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS +``` -???- note "Error Handling and Reverts" - The SDK defines several custom errors to help developers handle common issues like incorrect gas fees, invalid senders, and more. For example, `InvalidMsgValue` is thrown when the message value for a relayed message is erroneous. +Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. - ```solidity - error InvalidMsgValue(uint256 msgValue, uint256 totalFee); +???- example "Fetch transaction history for a specific address" + ```bash + curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" ``` -## Usage - -This section covers cross-chain messaging and token transfers and shows how to use the Wormhole Solidity SDK in real-world scenarios. +## How can I manually submit a VAA to a destination chain in the correct format? -### Send a Cross-Chain Message +To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: -To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: +1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format -```solidity -pragma solidity ^0.8.19; + ```bash + https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced + ``` -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; +2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python -contract CrossChainSender is Base { - constructor( - address _wormholeRelayer, - address _wormhole - ) Base(_wormholeRelayer, _wormhole) {} +3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - function sendMessage( - bytes memory message, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Register sender and send message through WormholeRelayer - setRegisteredSender(targetChain, msg.sender); - onlyWormholeRelayer().sendPayloadToEvm( - targetChain, - address(targetAddress), - message, - 0, - 500_000 - ); - } -} -``` + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section -This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. + - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field -### Send Tokens Across Chains +Following these steps, you can manually submit a VAA in the proper format to a destination chain. +--- END CONTENT --- -The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. +Doc-Content: https://wormhole.com/docs/..build/transfers/cctp/ +--- BEGIN CONTENT --- +--- +title: Interacting with CCTP Contracts +description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. +categories: Transfer +--- -```solidity -pragma solidity ^0.8.19; +# Get Started with CCTP -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; +## Introduction -contract CrossChainTokenSender is TokenSender { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenSender(_wormholeRelayer, _wormhole) {} +Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. - function sendToken( - address token, - uint256 amount, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Send tokens across chains - transferTokenToTarget(token, amount, targetChain, targetAddress); - } -} -``` +As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. -In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. +This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. -### Receive Tokens Across Chains +## Prerequisites -To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. +To interact with the Wormhole CCTP, you'll need the following: -```solidity -pragma solidity ^0.8.19; +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; +## Wormhole's CCTP Integration Contract -contract CrossChainTokenReceiver is TokenReceiver { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenReceiver(_wormholeRelayer, _wormhole) {} +Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). - // Function to handle received tokens from another chain - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable override { - // Process the received tokens here - receiveTokens(payload); - } -} -``` +The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. -In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. +This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. !!! note - Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/products/messaging/guides/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. -## Testing Environment +??? code "Circle Integration contract" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; -The SDK includes built-in support for Forge-based testing, which allows you to test your cross-chain applications locally before deploying them to production. Testing with the same Solidity compiler version and configuration you plan to use in production is highly recommended to catch any potential issues early. +import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IWormhole} from "wormhole/interfaces/IWormhole.sol"; +import {BytesLib} from "wormhole/libraries/external/BytesLib.sol"; -For a detailed example, check out the below repositories: +import {ICircleBridge} from "../interfaces/circle/ICircleBridge.sol"; + +import {CircleIntegrationGovernance} from "./CircleIntegrationGovernance.sol"; +import {CircleIntegrationMessages} from "./CircleIntegrationMessages.sol"; + +/** + * @notice This contract burns and mints Circle-supported tokens by using Circle's Cross-Chain Transfer Protocol. It also emits + * Wormhole messages with arbitrary payloads to allow for additional composability when performing cross-chain + * transfers of Circle-suppored assets. + */ +contract CircleIntegration is + CircleIntegrationMessages, + CircleIntegrationGovernance, + ReentrancyGuard +{ + using BytesLib for bytes; + + /** + * @notice Emitted when Circle-supported assets have been minted to the mintRecipient + * @param emitterChainId Wormhole chain ID of emitter contract on source chain + * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on source chain + * @param sequence Sequence of Wormhole message used to mint tokens + */ + event Redeemed( + uint16 indexed emitterChainId, + bytes32 indexed emitterAddress, + uint64 indexed sequence + ); + + /** + * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits + * a Wormhole message containing a user-specified payload with instructions for what to do with + * the Circle-supported assets once they have been minted on the target chain. + * @dev reverts if: + * - user passes insufficient value to pay Wormhole message fee + * - `token` is not supported by Circle Bridge + * - `amount` is zero + * - `targetChain` is not supported + * - `mintRecipient` is bytes32(0) + * @param transferParams Struct containing the following attributes: + * - `token` Address of the token to be burned + * - `amount` Amount of `token` to be burned + * - `targetChain` Wormhole chain ID of the target blockchain + * - `mintRecipient` The recipient wallet or contract address on the target chain + * @param batchId ID for Wormhole message batching + * @param payload Arbitrary payload to be delivered to the target chain via Wormhole + * @return messageSequence Wormhole sequence number for this contract + */ + function transferTokensWithPayload( + TransferParameters memory transferParams, + uint32 batchId, + bytes memory payload + ) public payable nonReentrant returns (uint64 messageSequence) { + // cache wormhole instance and fees to save on gas + IWormhole wormhole = wormhole(); + uint256 wormholeFee = wormhole.messageFee(); - - [Cross chain messaging](/docs/products/messaging/tutorials/cross-chain-contracts/){target=\_blank} - - [Cross chain token transfer](/docs/products/messaging/tutorials/cross-chain-token-contracts/){target=\_blank} ---- END CONTENT --- + // confirm that the caller has sent enough ether to pay for the wormhole message fee + require(msg.value == wormholeFee, "insufficient value"); -Doc-Content: https://wormhole.com/docs/build/toolkit/typescript-sdk/ ---- BEGIN CONTENT --- ---- -title: Wormhole SDK -description: The Wormhole SDK provides tools for cross-chain communication, token bridges, and more, enabling developers to integrate with multiple blockchain environments. -categories: Typescript-SDK ---- + // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` + // should be the target contract (or wallet) composing on this contract. + (uint64 nonce, uint256 amountReceived) = _transferTokens( + transferParams.token, + transferParams.amount, + transferParams.targetChain, + transferParams.mintRecipient + ); -# Wormhole SDK + // encode DepositWithPayload message + bytes memory encodedMessage = encodeDepositWithPayload( + DepositWithPayload({ + token: addressToBytes32(transferParams.token), + amount: amountReceived, + sourceDomain: localDomain(), + targetDomain: getDomainFromChainId(transferParams.targetChain), + nonce: nonce, + fromAddress: addressToBytes32(msg.sender), + mintRecipient: transferParams.mintRecipient, + payload: payload + }) + ); -## Get Started + // send the DepositWithPayload wormhole message + messageSequence = wormhole.publishMessage{value: wormholeFee}( + batchId, + encodedMessage, + wormholeFinality() + ); + } -The Wormhole SDK provides developers with essential tools for cross-chain communication, token bridges, and more. This SDK enables seamless interaction between different blockchain environments with a focus on performance and usability. + function _transferTokens( + address token, + uint256 amount, + uint16 targetChain, + bytes32 mintRecipient + ) internal returns (uint64 nonce, uint256 amountReceived) { + // sanity check user input + require(amount > 0, "amount must be > 0"); + require(mintRecipient != bytes32(0), "invalid mint recipient"); + require(isAcceptedToken(token), "token not accepted"); + require( + getRegisteredEmitter(targetChain) != bytes32(0), + "target contract not registered" + ); -
+ // take custody of tokens + amountReceived = custodyTokens(token, amount); -- :octicons-book-16:{ .lg .middle } **Wormhole SDK** + // cache Circle Bridge instance + ICircleBridge circleBridge = circleBridge(); - --- + // approve the Circle Bridge to spend tokens + SafeERC20.safeApprove( + IERC20(token), + address(circleBridge), + amountReceived + ); - Learn about the core functionalities of the Wormhole SDK, including how to use its features for building cross-chain applications. + // burn tokens on the bridge + nonce = circleBridge.depositForBurnWithCaller( + amountReceived, + getDomainFromChainId(targetChain), + mintRecipient, + token, + getRegisteredEmitter(targetChain) + ); + } - [:custom-arrow: Explore the SDK](/docs/tools/typescript-sdk/sdk-reference/) + function custodyTokens( + address token, + uint256 amount + ) internal returns (uint256) { + // query own token balance before transfer + (, bytes memory queriedBalanceBefore) = token.staticcall( + abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) + ); + uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); -- :octicons-code-16:{ .lg .middle } **Layouts** + // deposit tokens + SafeERC20.safeTransferFrom( + IERC20(token), + msg.sender, + address(this), + amount + ); - --- + // query own token balance after transfer + (, bytes memory queriedBalanceAfter) = token.staticcall( + abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) + ); + uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - Discover how to define, serialize, and deserialize data structures using the Wormhole SDK's layout system, ensuring efficient cross-chain communication. + return balanceAfter - balanceBefore; + } - [:custom-arrow: Learn about layouts](/docs/tools/typescript-sdk/guides/sdk-layout/) + /** + * @notice `redeemTokensWithPayload` verifies the Wormhole message from the source chain and + * verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge + * contract by passing the Circle message and attestation to mint tokens to the specified + * mint recipient. It also verifies that the caller is the specified mint recipient to ensure + * atomic execution of the additional instructions in the Wormhole message. + * @dev reverts if: + * - Wormhole message is not properly attested + * - Wormhole message was not emitted from a registered contrat + * - Wormhole message was already consumed by this contract + * - msg.sender is not the encoded mintRecipient + * - Circle Bridge message and Wormhole message are not associated + * - `receiveMessage` call to Circle Transmitter fails + * @param params Struct containing the following attributes: + * - `encodedWormholeMessage` Wormhole message emitted by a registered contract including + * information regarding the token burn on the source chain and an arbitrary message. + * - `circleBridgeMessage` Message emitted by Circle Bridge contract with information regarding + * the token burn on the source chain. + * - `circleAttestation` Serialized EC Signature attesting the cross-chain transfer + * @return depositInfo Struct containing the following attributes: + * - `token` Address (bytes32 left-zero-padded) of token to be minted + * - `amount` Amount of tokens to be minted + * - `sourceDomain` Circle domain for the source chain + * - `targetDomain` Circle domain for the target chain + * - `nonce` Circle sequence number for the transfer + * - `fromAddress` Source CircleIntegration contract caller's address + * - `mintRecipient` Recipient of minted tokens (must be caller of this contract) + * - `payload` Arbitrary Wormhole message payload + */ + function redeemTokensWithPayload( + RedeemParameters calldata params + ) public returns (DepositWithPayload memory depositInfo) { + // verify the wormhole message + IWormhole.VM memory verifiedMessage = verifyWormholeRedeemMessage( + params.encodedWormholeMessage + ); -
---- END CONTENT --- + // Decode the message payload into the DepositWithPayload struct. Call the Circle TokenMinter + // contract to determine the address of the encoded token on this chain. + depositInfo = decodeDepositWithPayload(verifiedMessage.payload); + depositInfo.token = fetchLocalTokenAddress( + depositInfo.sourceDomain, + depositInfo.token + ); -Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ ---- BEGIN CONTENT --- ---- -title: Building Protocols and Payloads -description: Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. -categories: Typescript-SDK ---- + // confirm that circle gave us a valid token address + require(depositInfo.token != bytes32(0), "invalid local token address"); -# Building Protocols and Payloads + // confirm that the caller is the `mintRecipient` to ensure atomic execution + require( + addressToBytes32(msg.sender) == depositInfo.mintRecipient, + "caller must be mintRecipient" + ); -## Introduction + // confirm that the caller passed the correct message pair + require( + verifyCircleMessage( + params.circleBridgeMessage, + depositInfo.sourceDomain, + depositInfo.targetDomain, + depositInfo.nonce + ), + "invalid message pair" + ); -The [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} provides a flexible and powerful system for integrating cross-chain communication into your applications. A key feature of the SDK is its ability to define protocols—modular units representing distinct functionalities—and their associated payloads, which encapsulate the data required for specific operations within those protocols. + // call the circle bridge to mint tokens to the recipient + bool success = circleTransmitter().receiveMessage( + params.circleBridgeMessage, + params.circleAttestation + ); + require(success, "CIRCLE_INTEGRATION: failed to mint tokens"); -This guide will help you understand how to build protocols and payloads in the SDK, covering: + // emit Redeemed event + emit Redeemed( + verifiedMessage.emitterChainId, + verifiedMessage.emitterAddress, + verifiedMessage.sequence + ); + } - - The role of protocols and payloads in cross-chain communication - - The mechanics of registering protocols and payloads using the SDK - - Best practices for creating strongly typed layouts to ensure compatibility and reliability - - Real-world examples using the `TokenBridge` as a reference implementation + function verifyWormholeRedeemMessage( + bytes memory encodedMessage + ) internal returns (IWormhole.VM memory) { + require(evmChain() == block.chainid, "invalid evm chain"); -By the end of this guide, you’ll have a solid understanding of how to define, register, and use protocols and payloads in your projects. + // parse and verify the Wormhole core message + ( + IWormhole.VM memory verifiedMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -## What is a Protocol? + // confirm that the core layer verified the message + require(valid, reason); -In the Wormhole SDK, a protocol represents a significant feature or functionality that operates across multiple blockchains. Protocols provide the framework for handling specific types of messages, transactions, or operations consistently and standardized. + // verify that this message was emitted by a trusted contract + require(verifyEmitter(verifiedMessage), "unknown emitter"); -Examples of Protocols: + // revert if this message has been consumed already + require( + !isMessageConsumed(verifiedMessage.hash), + "message already consumed" + ); + consumeMessage(verifiedMessage.hash); - - **`TokenBridge`** - enables cross-chain token transfers, including operations like transferring tokens and relaying payloads - - **`NTT (Native Token Transfers)`** - manages native token movements across chains + return verifiedMessage; + } -Protocols are defined by: + function verifyEmitter( + IWormhole.VM memory vm + ) internal view returns (bool) { + // verify that the sender of the wormhole message is a trusted + return (getRegisteredEmitter(vm.emitterChainId) == vm.emitterAddress && + vm.emitterAddress != bytes32(0)); + } - - **A `name`** - a string identifier (e.g., `TokenBridge`, `Ntt`) - - **A set of `payloads`** - these represent the specific actions or messages supported by the protocol, such as `Transfer` or `TransferWithPayload` + function verifyCircleMessage( + bytes memory circleMessage, + uint32 sourceDomain, + uint32 targetDomain, + uint64 nonce + ) internal pure returns (bool) { + // parse the circle bridge message inline + uint32 circleSourceDomain = circleMessage.toUint32(4); + uint32 circleTargetDomain = circleMessage.toUint32(8); + uint64 circleNonce = circleMessage.toUint64(12); -Each protocol is registered in the Wormhole SDK, allowing developers to leverage its predefined features or extend it with custom payloads. + // confirm that both the Wormhole message and Circle message share the same transfer info + return (sourceDomain == circleSourceDomain && + targetDomain == circleTargetDomain && + nonce == circleNonce); + } -## What is a Payload? + /** + * @notice Fetches the local token address given an address and domain from + * a different chain. + * @param sourceDomain Circle domain for the sending chain. + * @param sourceToken Address of the token for the sending chain. + * @return Address bytes32 formatted address of the `sourceToken` on this chain. + */ + function fetchLocalTokenAddress( + uint32 sourceDomain, + bytes32 sourceToken + ) public view returns (bytes32) { + return + addressToBytes32( + circleTokenMinter().remoteTokensToLocalTokens( + keccak256(abi.encodePacked(sourceDomain, sourceToken)) + ) + ); + } -A payload is a structured piece of data that encapsulates the details of a specific operation within a protocol. It defines the format, fields, and types of data used in a message or transaction. Payloads ensure consistency and type safety when handling complex cross-chain operations. + /** + * @notice Converts type address to bytes32 (left-zero-padded) + * @param address_ Address to convert to bytes32 + * @return Address bytes32 + */ + function addressToBytes32(address address_) public pure returns (bytes32) { + return bytes32(uint256(uint160(address_))); + } +} + ``` -Each payload is defined as: +The functions provided by the Circle Integration contract are as follows: - - **A `layout`** - describes the binary format of the payload fields - - **A `literal`** - combines the protocol name and payload name into a unique identifier (e.g., `TokenBridge:Transfer`) +- **`transferTokensWithPayload`** - calls the Circle Bridge contract to burn Circle-supported tokens. It emits a Wormhole message containing a user-specified payload with instructions for what to do with the Circle-supported assets once they have been minted on the target chain -By registering payloads, developers can enforce type safety and enable serialization and deserialization for specific protocol operations. + ??? interface "Parameters" -## Register Protocols and Payloads + `transferParams` ++"TransferParameters"++ -Protocols and payloads work together to enable cross-chain communication with precise type safety. For instance, in the `TokenBridge` protocol: + A tuple containing the parameters for the transfer. - - The protocol is registered under the `TokenBridge` namespace - - Payloads like `Transfer` or `AttestMeta` are linked to the protocol to handle specific operations + ??? child "`TransferParameters` struct" -Understanding the connection between these components is important for customizing or extending the SDK to suit your needs. + `token` ++"address"++ -### Register Protocols + Address of the token to be burned. -Registering a protocol establishes its connection to Wormhole's infrastructure, ensuring it interacts seamlessly with payloads and platforms while maintaining type safety and consistency. + --- -#### How Protocol Registration Works + `amount` ++"uint256"++ -Protocol registration involves two key tasks: + Amount of the token to be burned. - - **Mapping protocols to interfaces** - connect the protocol to its corresponding interface, defining its expected behavior across networks (`N`) and chains (`C`). This ensures type safety, similar to strong typing, by preventing runtime errors if protocol definitions are incorrect - - **Linking protocols to platforms** - specify platform-specific implementations if needed, or use default mappings for platform-agnostic protocols + --- -For example, here's the `TokenBridge` protocol registration: + `targetChain` ++"uint16"++ -```typescript -declare module '../../registry.js' { - export namespace WormholeRegistry { - interface ProtocolToInterfaceMapping { - TokenBridge: TokenBridge; - } - interface ProtocolToPlatformMapping { - TokenBridge: EmptyPlatformMap<'TokenBridge'>; - } - } -} - -``` + Wormhole chain ID of the target blockchain. -This code snippet: + --- - - Maps the `TokenBridge` protocol to its interface to define how it operates - - Links the protocol to a default platform mapping via `EmptyPlatformMap` + `mintRecipient` ++"bytes32"++ -You can view the full implementation in the [`TokenBridge` protocol file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L14-L70){target=\_blank}. + The recipient wallet or contract address on the target chain. -#### Platform-Specific Protocols + --- -Some protocols require platform-specific behavior. For instance, the EVM-compatible Wormhole Registry maps native addresses for Ethereum-based chains: + `batchId` ++"uint32"++ -```typescript -declare module '@wormhole-foundation/sdk-connect' { - export namespace WormholeRegistry { - interface PlatformToNativeAddressMapping { - Evm: EvmAddress; - } - } -} + The ID for Wormhole message batching. -registerNative(_platform, EvmAddress); -``` + --- -This ensures that `EvmAddress` is registered as the native address type for EVM-compatible platforms. See the [EVM platform address file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/platforms/evm/src/address.ts#L98-L106){target=\_blank} for details. + `payload` ++"bytes"++ -### Register Payloads + Arbitrary payload to be delivered to the target chain via Wormhole. -[Payload registration](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts){target=\_blank} enables developers to define, serialize, and handle custom message types within their protocols. It establishes the connection between a protocol and its payloads, ensuring seamless integration, type enforcement, and runtime efficiency. + ??? interface "Returns" -This process ties a protocol to its payloads using a combination of: + `messageSequence` ++"uint64"++ - - **Payload literals** - unique identifiers in the format `:`. These literals map each payload to a layout - - **Payload layouts** - structures that define the binary representation of payload data - - **The payload factory** - a centralized runtime registry that maps payload literals to layouts for dynamic resolution and serialization + Wormhole sequence number for this contract. -These components work together to streamline the definition and management of protocol payloads. +- `redeemTokensWithPayload` - verifies the Wormhole message from the source chain and verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge contract by passing the Circle message and attestation to the `receiveMessage` function, which is responsible for minting tokens to the specified mint recipient. It also verifies that the caller is the specified mint recipient to ensure atomic execution of the additional instructions in the Wormhole message -#### How Payload Registration Works + ??? interface "Parameters" -Payload registration involves: + `params` ++"RedeemParameters"++ -1. **Define payload layouts** - create layouts to structure your payloads. For instance, a protocol might use a `TransferWithPayload` layout: + A tuple containing the parameters for the redemption. - ```typescript - export const transferWithPayloadLayout = < - const P extends CustomizableBytes = undefined ->( - customPayload?: P -) => - [ - payloadIdItem(3), - ...transferCommonLayout, - { name: 'from', ...universalAddressItem }, - customizableBytes({ name: 'payload' }, customPayload), - ] as const; - ``` + ??? child "`RedeemParameters` struct" -2. **Register payloads** - use `registerPayloadTypes` to map payload literals to their layouts: + `encodedWormholeMessage` ++"bytes"++ - ```typescript - registerPayloadTypes('ProtocolName', protocolNamedPayloads); - ``` + Wormhole message emitted by a registered contract including information regarding the token burn on the source chain and an arbitrary message. -3. **Access registered payloads** - use the [`getPayloadLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/9105de290c91babbf8ad031bd89cc75ee38739c8/core/definitions/src/vaa/functions.ts#L19-L23){target=\_blank} function to fetch the layout for a specific payload literal. This method ensures that the correct layout is retrieved dynamically and safely: + --- - ```typescript - const layout = getPayloadLayout('ProtocolName:PayloadName'); - ``` + `circleBridgeMessage` ++"bytes"++ -These steps link payload literals and their layouts, enabling seamless runtime handling. + Message emitted by Circle Bridge contract with information regarding the token burn on the source chain. -#### The Payload Factory + --- -At the core of the payload registration process is the `payloadFactory`, a registry that manages the mapping between payload literals and layouts: + `circleAttestation` ++"bytes"++ -```typescript -export const payloadFactory = new Map(); + Serialized EC signature attesting the cross-chain transfer. -export function registerPayloadType( - protocol: ProtocolName, - name: string, - layout: Layout -) { - const payloadLiteral = composeLiteral(protocol, name); - if (payloadFactory.has(payloadLiteral)) { - throw new Error(`Payload type ${payloadLiteral} already registered`); - } - payloadFactory.set(payloadLiteral, layout); -} - -``` + ??? interface "Returns" - - The `payloadFactory` ensures each payload literal maps to its layout uniquely - - The [`registerPayloadType`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts#L46-L52){target=\_blank} function adds individual payloads, while [`registerPayloadTypes`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts#L62-L64){target=\_blank} supports bulk registration + `depositInfo` ++"DepositWithPayload"++ -This implementation ensures dynamic, efficient handling of payloads at runtime. + Information about the deposit. -## Integrate Protocols with Payloads + ??? child "`DepositWithPayload` struct" -Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}. + `token` ++"bytes32"++ -### Payload Discriminators + Address (`bytes32` left-zero-padded) of token to be minted. -Payload discriminators are mechanisms in the Wormhole SDK that dynamically identify and map incoming payloads to their respective layouts at runtime. They are relevant for protocols like `TokenBridge`, enabling efficient handling of diverse payload types while ensuring type safety and consistent integration. + --- -#### How Discriminators Work + `amount` ++"uint256"++ -Discriminators evaluate serialized binary data and determine the corresponding payload layout by inspecting fixed fields or patterns within the data. Each payload layout is associated with a payload literal (e.g., `TokenBridge:Transfer` or `TokenBridge:TransferWithPayload`). + Amount of tokens to be minted. + + --- -This system ensures: + `sourceDomain` ++"uint32"++ - - **Dynamic runtime identification** - payloads are parsed based on their content, even if a single protocol handles multiple payload types - - **Strict type enforcement** - discriminators leverage layout mappings to prevent invalid payloads from being processed + Circle domain for the source chain. -Below is an example of how the Wormhole SDK builds a discriminator to distinguish between payload layouts: + --- -```typescript -export function layoutDiscriminator( - layouts: readonly Layout[], - allowAmbiguous?: B -): Discriminator { - // Internal logic to determine distinguishable layouts - const [distinguishable, discriminator] = internalBuildDiscriminator(layouts); - if (!distinguishable && !allowAmbiguous) { - throw new Error('Cannot uniquely distinguish the given layouts'); - } + `targetDomain` ++"uint32"++ - return ( - !allowAmbiguous - ? (encoded: BytesType) => { - const layout = discriminator(encoded); - return layout.length === 0 ? null : layout[0]; - } - : discriminator - ) as Discriminator; -} - -``` + Circle domain for the target chain. - - [`layoutDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/9105de290c91babbf8ad031bd89cc75ee38739c8/core/base/src/utils/layout.ts#L16){target=\_blank} takes a list of layouts and generates a function that can identify the appropriate layout for a given serialized payload - - The `allowAmbiguous` parameter determines whether layouts with overlapping characteristics are permitted + --- -### Real-World Example: Token Bridge Protocol + `nonce` ++"uint64"++ -Integrating protocols with their respective payloads exemplifies how the Wormhole SDK leverages layouts and type-safe registration mechanisms to ensure efficient cross-chain communication. This section focuses on how protocols like `TokenBridge` use payloads to facilitate specific operations. + Circle sequence number for the transfer. -#### Token Bridge Protocol and Payloads + --- -The `TokenBridge` protocol enables cross-chain token transfers through its payloads. Key payloads include: + `fromAddress` ++"bytes32"++ - - **`Transfer`** - handles basic token transfer operations - - **`TransferWithPayload`** - extends the `Transfer` payload to include custom data, enhancing functionality + Source Circle Integration contract caller's address. -Payloads are registered to the `TokenBridge` protocol via the `PayloadLiteralToLayoutMapping` interface, which links payload literals (e.g., `TokenBridge:Transfer`) to their layouts. + --- -Additionally, the protocol uses reusable layouts like [`transferCommonLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L29C7-L47){target=\_blank} and extends them in more specialized layouts such as [`transferWithPayloadLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L49-L57){target=\_blank}: + `mintRecipient` ++"bytes32"++ -```typescript -export const transferWithPayloadLayout = < - const P extends CustomizableBytes = undefined ->( - customPayload?: P -) => - [ - payloadIdItem(3), - ...transferCommonLayout, - { name: 'from', ...universalAddressItem }, - customizableBytes({ name: 'payload' }, customPayload), - ] as const; -``` + Recipient of minted tokens (must be caller of this contract). -This layout includes: + --- + + `payload` ++"bytes"++ - - A `payloadIdItem` to identify the payload type - - Common fields for token and recipient details - - A customizable `payload` field for additional data + Arbitrary Wormhole message payload. -#### Use the Discriminator + ??? interface "Emits" -To manage multiple payloads, the `TokenBridge` protocol utilizes a discriminator to distinguish between payload types dynamically. For example: + `Redeemed` - event emitted when Circle-supported assets have been minted to the `mintRecipient` -```typescript -const tokenBridgePayloads = ['Transfer', 'TransferWithPayload'] as const; + ??? child "Event arguments" -export const getTransferDiscriminator = lazyInstantiate(() => - payloadDiscriminator([_protocol, tokenBridgePayloads]) -); -``` + `emitterChainId` ++"uint16"++ - - The [`getTransferDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L67-L70){target=\_blank} function dynamically evaluates payloads using predefined layouts - - This ensures that each payload type is processed according to its unique structure and type-safe layout + Wormhole chain ID of emitter contract on source chain. -#### Register Payloads to Protocols + --- -Here’s how the `TokenBridge` protocol connects its payloads to the Wormhole SDK: + `emitterAddress` ++"bytes32"++ -```typescript -declare module '../../registry.js' { - export namespace WormholeRegistry { - interface PayloadLiteralToLayoutMapping - extends RegisterPayloadTypes< - 'TokenBridge', - typeof tokenBridgeNamedPayloads - > {} - } -} + Address (`bytes32` zero-left-padded) of emitter on source chain. -registerPayloadTypes('TokenBridge', tokenBridgeNamedPayloads); -``` + --- -This registration links the `TokenBridge` payload literals to their respective layouts, enabling serialization and deserialization at runtime. + `sequence` ++"uint64"++ -You can explore the complete `TokenBridge` protocol and payload definitions in the [`TokenBridge` layout file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts){target=\_blank}. + Sequence of Wormhole message used to mint tokens. -#### Token Bridge Payloads +## Circle's CCTP Contracts -The following payloads are registered for the `TokenBridge` protocol: +Three key contracts power Circle's CCTP: - - **`AttestMeta`** - used for token metadata attestation - - **`Transfer`** - facilitates token transfers - - **`TransferWithPayload`** - adds a custom payload to token transfers +- **`TokenMessenger`** - the entry point for cross-chain USDC transfers, routing messages to initiate USDC burns on the source chain, and mint USDC on the destination chain +- **`MessageTransmitter`** - handles generic message passing, sending messages from the source chain and receiving them on the destination chain +- **`TokenMinter`** - responsible for the actual minting and burning of USDC, utilizing chain-specific settings for both the burners and minters across different networks -These payloads and their layouts are defined in the [`TokenBridge` layout file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts){target=\_blank}. +The following sections will examine these contracts in-depth, focusing on the methods invoked indirectly through function calls in the Wormhole Circle Integration contract. -### Other Protocols: Native Token Transfers (NTT) +!!! note + When using Wormhole's CCTP integration, you will not directly interact with these contracts. You will indirectly interact with them through the Wormhole Circle Integration contract. -While this guide focuses on the `TokenBridge` protocol, other protocols, like NTT, follow a similar structure. +These contracts can be found in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/){target=\_blank} on GitHub. - - NTT manages the transfer of native tokens across chains - - Payloads such as `WormholeTransfer` and `WormholeTransferStandardRelayer` are registered to the protocol using the same patterns for payload literals and layouts - - The same mechanisms for type-safe registration and payload discriminators apply, ensuring reliability and extensibility +### Token Messenger Contract -For more details, you can explore the [NTT implementation in the SDK](https://github.com/wormhole-foundation/example-native-token-transfers/blob/00f83aa215338b1b8fd66f522bd0f45be3e98a5a/sdk/definitions/src/ntt.ts){target=\_blank}. ---- END CONTENT --- +The Token Messenger contract enables cross-chain USDC transfers by coordinating message exchanges between blockchains. It works alongside the Message Transmitter contract to relay messages for burning USDC on a source chain and minting it on a destination chain. The contract emits events to track both the burning of tokens and their subsequent minting on the destination chain. -Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/sdk-layout/ ---- BEGIN CONTENT --- ---- -title: Data Layouts -description: Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. -categories: Typescript-SDK ---- +To ensure secure communication, the Token Messenger restricts message handling to registered remote Token Messenger contracts only. It verifies the proper conditions for token burning and manages local and remote minters using chain-specific settings. -# Data Layouts +Additionally, the contract provides methods for updating or replacing previously sent burn messages, adding or removing remote Token Messenger contracts, and managing the minting process for cross-chain transfers. -## Introduction +??? code "Token Messenger contract" + ```solidity + /* + * Copyright (c) 2022, Circle Internet Financial Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +pragma solidity 0.7.6; -The [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} uses the [layout package](https://www.npmjs.com/package/binary-layout){target=\_blank} to define, serialize, and deserialize data structures efficiently. This modular system ensures consistent data formatting and cross-environment compatibility, benefiting projects that require robust handling of structured data. +import "./interfaces/IMessageHandler.sol"; +import "./interfaces/ITokenMinter.sol"; +import "./interfaces/IMintBurnToken.sol"; +import "./interfaces/IMessageTransmitter.sol"; +import "./messages/BurnMessage.sol"; +import "./messages/Message.sol"; +import "./roles/Rescuable.sol"; -By understanding the layout mechanism, you’ll be able to: +/** + * @title TokenMessenger + * @notice Sends messages and receives messages to/from MessageTransmitters + * and to/from TokenMinters + */ +contract TokenMessenger is IMessageHandler, Rescuable { + // ============ Events ============ + /** + * @notice Emitted when a DepositForBurn message is sent + * @param nonce unique nonce reserved by message + * @param burnToken address of token burnt on source domain + * @param amount deposit amount + * @param depositor address where deposit is transferred from + * @param mintRecipient address receiving minted tokens on destination domain as bytes32 + * @param destinationDomain destination domain + * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32 + * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). + * If equal to bytes32(0), any address can call receiveMessage(). + */ + event DepositForBurn( + uint64 indexed nonce, + address indexed burnToken, + uint256 amount, + address indexed depositor, + bytes32 mintRecipient, + uint32 destinationDomain, + bytes32 destinationTokenMessenger, + bytes32 destinationCaller + ); - - Define data structures (numbers, arrays, and custom types) - - Efficiently serialize and deserialize data using the SDK’s utilities - - Handle protocol-specific layouts with ease + /** + * @notice Emitted when tokens are minted + * @param mintRecipient recipient address of minted tokens + * @param amount amount of minted tokens + * @param mintToken contract address of minted token + */ + event MintAndWithdraw( + address indexed mintRecipient, + uint256 amount, + address indexed mintToken + ); -This guide is beneficial for developers looking to integrate Wormhole into their applications or protocols, especially those dealing with complex payloads or cross-chain communication. + /** + * @notice Emitted when a remote TokenMessenger is added + * @param domain remote domain + * @param tokenMessenger TokenMessenger on remote domain + */ + event RemoteTokenMessengerAdded(uint32 domain, bytes32 tokenMessenger); -## Key Concepts + /** + * @notice Emitted when a remote TokenMessenger is removed + * @param domain remote domain + * @param tokenMessenger TokenMessenger on remote domain + */ + event RemoteTokenMessengerRemoved(uint32 domain, bytes32 tokenMessenger); -### Layout Items + /** + * @notice Emitted when the local minter is added + * @param localMinter address of local minter + * @notice Emitted when the local minter is added + */ + event LocalMinterAdded(address localMinter); -A layout defines how data structures should be serialized (converted into binary format) and deserialized (converted back into their original structure). This ensures consistent data formatting when transmitting information across different blockchain environments. + /** + * @notice Emitted when the local minter is removed + * @param localMinter address of local minter + * @notice Emitted when the local minter is removed + */ + event LocalMinterRemoved(address localMinter); -Layouts are composed of [layout items](https://github.com/nonergodic/layout/blob/main/src/items.ts){target=\_blank}, which describe individual fields or sets of fields in your data. Each layout item specifies: + // ============ Libraries ============ + using TypedMemView for bytes; + using TypedMemView for bytes29; + using BurnMessage for bytes29; + using Message for bytes29; - - **`name`** - name of the field - - **`binary`** - type of data (e.g., `uint`, `bytes`) - - **`size`** - byte length for fixed-size fields within uint and bytes items only + // ============ State Variables ============ + // Local Message Transmitter responsible for sending and receiving messages to/from remote domains + IMessageTransmitter public immutable localMessageTransmitter; -Layout items can represent: + // Version of message body format + uint32 public immutable messageBodyVersion; - - **Primitive types** - basic data types like unsigned integers (`uint`) or byte arrays (`bytes`) - - **Composite types** - more complex structures, such as arrays or nested objects + // Minter responsible for minting and burning tokens on the local domain + ITokenMinter public localMinter; -Below is an example of a layout that might be used to serialize a message across the Wormhole protocol: + // Valid TokenMessengers on remote domains + mapping(uint32 => bytes32) public remoteTokenMessengers; -```typescript -const exampleLayout = [ - { name: 'sourceChain', binary: 'uint', size: 2 }, - { name: 'orderSender', binary: 'bytes', size: 32 }, - { name: 'redeemer', binary: 'bytes', size: 32 }, - { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 }, -] as const; -``` + // ============ Modifiers ============ + /** + * @notice Only accept messages from a registered TokenMessenger contract on given remote domain + * @param domain The remote domain + * @param tokenMessenger The address of the TokenMessenger contract for the given remote domain + */ + modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) { + require( + _isRemoteTokenMessenger(domain, tokenMessenger), + "Remote TokenMessenger unsupported" + ); + _; + } -In this example: + /** + * @notice Only accept messages from the registered message transmitter on local domain + */ + modifier onlyLocalMessageTransmitter() { + // Caller must be the registered message transmitter for this domain + require(_isLocalMessageTransmitter(), "Invalid message transmitter"); + _; + } - - `sourceChain` is a 2-byte unsigned integer (`uint`) identifying the source blockchain - - `orderSender` is a fixed-length 32-byte array representing the sender's address - - `redeemer` is another 32-byte array used for the redeemer’s address - - `redeemerMessage` is a variable-length byte sequence, with its length specified by a 4-byte integer + // ============ Constructor ============ + /** + * @param _messageTransmitter Message transmitter address + * @param _messageBodyVersion Message body version + */ + constructor(address _messageTransmitter, uint32 _messageBodyVersion) { + require( + _messageTransmitter != address(0), + "MessageTransmitter not set" + ); + localMessageTransmitter = IMessageTransmitter(_messageTransmitter); + messageBodyVersion = _messageBodyVersion; + } -This layout definition ensures that all necessary data fields are consistently encoded and can be correctly interpreted when they are deserialized. + // ============ External Functions ============ + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. + * Emits a `DepositForBurn` event. + * @dev reverts if: + * - given burnToken is not supported + * - given destinationDomain has no TokenMessenger registered + * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance + * to this contract is less than `amount`. + * - burn() reverts. For example, if `amount` is 0. + * - MessageTransmitter returns false or reverts. + * @param amount amount of tokens to burn + * @param destinationDomain destination domain + * @param mintRecipient address of mint recipient on destination domain + * @param burnToken address of contract to burn deposited tokens, on local domain + * @return _nonce unique nonce reserved by message + */ + function depositForBurn( + uint256 amount, + uint32 destinationDomain, + bytes32 mintRecipient, + address burnToken + ) external returns (uint64 _nonce) { + return + _depositForBurn( + amount, + destinationDomain, + mintRecipient, + burnToken, + // (bytes32(0) here indicates that any address can call receiveMessage() + // on the destination domain, triggering mint to specified `mintRecipient`) + bytes32(0) + ); + } -### Serialization and Deserialization + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint + * on the destination domain must be called by `destinationCaller`. + * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible + * to broadcast the message on the destination domain. This is an advanced feature, and the standard + * depositForBurn() should be preferred for use cases where a specific destination caller is not required. + * Emits a `DepositForBurn` event. + * @dev reverts if: + * - given destinationCaller is zero address + * - given burnToken is not supported + * - given destinationDomain has no TokenMessenger registered + * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance + * to this contract is less than `amount`. + * - burn() reverts. For example, if `amount` is 0. + * - MessageTransmitter returns false or reverts. + * @param amount amount of tokens to burn + * @param destinationDomain destination domain + * @param mintRecipient address of mint recipient on destination domain + * @param burnToken address of contract to burn deposited tokens, on local domain + * @param destinationCaller caller on the destination domain, as bytes32 + * @return nonce unique nonce reserved by message + */ + function depositForBurnWithCaller( + uint256 amount, + uint32 destinationDomain, + bytes32 mintRecipient, + address burnToken, + bytes32 destinationCaller + ) external returns (uint64 nonce) { + // Destination caller must be nonzero. To allow any destination caller, use depositForBurn(). + require(destinationCaller != bytes32(0), "Invalid destination caller"); -Serialization converts structured data into binary format; deserialization reverses this, reconstructing the original objects. + return + _depositForBurn( + amount, + destinationDomain, + mintRecipient, + burnToken, + destinationCaller + ); + } -You can serialize data using the `serializeLayout` function: + /** + * @notice Replace a BurnMessage to change the mint recipient and/or + * destination caller. Allows the sender of a previous BurnMessage + * (created by depositForBurn or depositForBurnWithCaller) + * to send a new BurnMessage to replace the original. + * The new BurnMessage will reuse the amount and burn token of the original, + * without requiring a new deposit. + * @dev The new message will reuse the original message's nonce. For a + * given nonce, all replacement message(s) and the original message are + * valid to broadcast on the destination domain, until the first message + * at the nonce confirms, at which point all others are invalidated. + * Note: The msg.sender of the replaced message must be the same as the + * msg.sender of the original message. + * @param originalMessage original message bytes (to replace) + * @param originalAttestation original attestation bytes + * @param newDestinationCaller the new destination caller, which may be the + * same as the original destination caller, a new destination caller, or an empty + * destination caller (bytes32(0), indicating that any destination caller is valid.) + * @param newMintRecipient the new mint recipient, which may be the same as the + * original mint recipient, or different. + */ + function replaceDepositForBurn( + bytes calldata originalMessage, + bytes calldata originalAttestation, + bytes32 newDestinationCaller, + bytes32 newMintRecipient + ) external { + bytes29 _originalMsg = originalMessage.ref(0); + _originalMsg._validateMessageFormat(); + bytes29 _originalMsgBody = _originalMsg._messageBody(); + _originalMsgBody._validateBurnMessageFormat(); -```typescript -const serialized = serializeLayout(fillLayout, exampleFill); -``` + bytes32 _originalMsgSender = _originalMsgBody._getMessageSender(); + // _originalMsgSender must match msg.sender of original message + require( + msg.sender == Message.bytes32ToAddress(_originalMsgSender), + "Invalid sender for message" + ); + require( + newMintRecipient != bytes32(0), + "Mint recipient must be nonzero" + ); -To deserialize the binary data back into a structured object, use the `deserializeLayout` function: + bytes32 _burnToken = _originalMsgBody._getBurnToken(); + uint256 _amount = _originalMsgBody._getAmount(); -```typescript -const deserialized = deserializeLayout(fillLayout, serialized); -``` + bytes memory _newMessageBody = BurnMessage._formatMessage( + messageBodyVersion, + _burnToken, + newMintRecipient, + _amount, + _originalMsgSender + ); -### Custom Conversions + localMessageTransmitter.replaceMessage( + originalMessage, + originalAttestation, + _newMessageBody, + newDestinationCaller + ); -Layouts also allow for custom conversions, which help map complex or custom types (like chain IDs or universal addresses) into a more usable format. This is useful when serializing or deserializing data that doesn’t fit neatly into simple types like integers or byte arrays. + emit DepositForBurn( + _originalMsg._nonce(), + Message.bytes32ToAddress(_burnToken), + _amount, + msg.sender, + newMintRecipient, + _originalMsg._destinationDomain(), + _originalMsg._recipient(), + newDestinationCaller + ); + } -For example, consider a custom conversion for a chain ID: + /** + * @notice Handles an incoming message received by the local MessageTransmitter, + * and takes the appropriate action. For a burn message, mints the + * associated token to the requested recipient on the local domain. + * @dev Validates the local sender is the local MessageTransmitter, and the + * remote sender is a registered remote TokenMessenger for `remoteDomain`. + * @param remoteDomain The domain where the message originated from. + * @param sender The sender of the message (remote TokenMessenger). + * @param messageBody The message body bytes. + * @return success Bool, true if successful. + */ + function handleReceiveMessage( + uint32 remoteDomain, + bytes32 sender, + bytes calldata messageBody + ) + external + override + onlyLocalMessageTransmitter + onlyRemoteTokenMessenger(remoteDomain, sender) + returns (bool) + { + bytes29 _msg = messageBody.ref(0); + _msg._validateBurnMessageFormat(); + require( + _msg._getVersion() == messageBodyVersion, + "Invalid message body version" + ); -```typescript -const chainCustomConversion = { - to: (chainId: number) => toChain(chainId), - from: (chain: Chain) => chainToChainId(chain), -} satisfies CustomConversion; - -``` + bytes32 _mintRecipient = _msg._getMintRecipient(); + bytes32 _burnToken = _msg._getBurnToken(); + uint256 _amount = _msg._getAmount(); -This setup allows Wormhole to convert between human-readable formats and binary-encoded data used in payloads. + ITokenMinter _localMinter = _getLocalMinter(); -### Error Handling + _mintAndWithdraw( + address(_localMinter), + remoteDomain, + _burnToken, + Message.bytes32ToAddress(_mintRecipient), + _amount + ); -The layout system performs error checks during serialization and deserialization. An error is thrown if data is incorrectly sized or in the wrong format. Refer to the below example: + return true; + } -```typescript -try { - deserializeLayout(fillLayout, corruptedData); -} catch (error) { - console.error('Error during deserialization:', error.message); -} -``` + /** + * @notice Add the TokenMessenger for a remote domain. + * @dev Reverts if there is already a TokenMessenger set for domain. + * @param domain Domain of remote TokenMessenger. + * @param tokenMessenger Address of remote TokenMessenger as bytes32. + */ + function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) + external + onlyOwner + { + require(tokenMessenger != bytes32(0), "bytes32(0) not allowed"); -## Application of Layouts + require( + remoteTokenMessengers[domain] == bytes32(0), + "TokenMessenger already set" + ); -This section will focus on applying the concepts explained earlier through examples. These will help developers better understand how to define layouts, serialize and deserialize data, and use custom conversions where needed. + remoteTokenMessengers[domain] = tokenMessenger; + emit RemoteTokenMessengerAdded(domain, tokenMessenger); + } -### Defining Layouts + /** + * @notice Remove the TokenMessenger for a remote domain. + * @dev Reverts if there is no TokenMessenger set for `domain`. + * @param domain Domain of remote TokenMessenger + */ + function removeRemoteTokenMessenger(uint32 domain) external onlyOwner { + // No TokenMessenger set for given remote domain. + require( + remoteTokenMessengers[domain] != bytes32(0), + "No TokenMessenger set" + ); -To get started with layouts in Wormhole, you need to define your structure. A layout is simply a list of fields (layout items) describing how each data piece will be serialized. + bytes32 _removedTokenMessenger = remoteTokenMessengers[domain]; + delete remoteTokenMessengers[domain]; + emit RemoteTokenMessengerRemoved(domain, _removedTokenMessenger); + } -Consider the following layout for a payload: + /** + * @notice Add minter for the local domain. + * @dev Reverts if a minter is already set for the local domain. + * @param newLocalMinter The address of the minter on the local domain. + */ + function addLocalMinter(address newLocalMinter) external onlyOwner { + require(newLocalMinter != address(0), "Zero address not allowed"); -```typescript -const exampleLayout = [ - { name: 'sourceChain', binary: 'uint', size: 2 }, - { name: 'orderSender', binary: 'bytes', size: 32 }, - { name: 'redeemer', binary: 'bytes', size: 32 }, - { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 }, -] as const; -``` + require( + address(localMinter) == address(0), + "Local minter is already set." + ); -In this example: + localMinter = ITokenMinter(newLocalMinter); - - `sourceChain` is an unsigned integer (uint) of 2 bytes - - `orderSender` is a 32-byte fixed-length byte array - - `redeemer` is another 32-byte byte array - - `redeemerMessage` is a length-prefixed byte array, with the length specified by a 4-byte integer + emit LocalMinterAdded(newLocalMinter); + } -### Serialize Data + /** + * @notice Remove the minter for the local domain. + * @dev Reverts if the minter of the local domain is not set. + */ + function removeLocalMinter() external onlyOwner { + address _localMinterAddress = address(localMinter); + require(_localMinterAddress != address(0), "No local minter is set."); -Once a layout is defined, the next step is to serialize data according to that structure. You can accomplish this using the `serializeLayout` function from the Wormhole SDK. + delete localMinter; + emit LocalMinterRemoved(_localMinterAddress); + } -```typescript -const examplePayload = { - sourceChain: 6, - orderSender: new Uint8Array(32), - redeemer: new Uint8Array(32), - redeemerMessage: new Uint8Array([0x01, 0x02, 0x03]), -}; + // ============ Internal Utils ============ + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. + * Emits a `DepositForBurn` event. + * @param _amount amount of tokens to burn (must be non-zero) + * @param _destinationDomain destination domain + * @param _mintRecipient address of mint recipient on destination domain + * @param _burnToken address of contract to burn deposited tokens, on local domain + * @param _destinationCaller caller on the destination domain, as bytes32 + * @return nonce unique nonce reserved by message + */ + function _depositForBurn( + uint256 _amount, + uint32 _destinationDomain, + bytes32 _mintRecipient, + address _burnToken, + bytes32 _destinationCaller + ) internal returns (uint64 nonce) { + require(_amount > 0, "Amount must be nonzero"); + require(_mintRecipient != bytes32(0), "Mint recipient must be nonzero"); -const serializedData = serializeLayout(exampleLayout, examplePayload); -``` + bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger( + _destinationDomain + ); -This takes the data structure (`examplePayload`) and serializes it according to the rules defined in the layout (`exampleLayout`). The result is a `Uint8Array` representing the serialized binary data. + ITokenMinter _localMinter = _getLocalMinter(); + IMintBurnToken _mintBurnToken = IMintBurnToken(_burnToken); + require( + _mintBurnToken.transferFrom( + msg.sender, + address(_localMinter), + _amount + ), + "Transfer operation failed" + ); + _localMinter.burn(_burnToken, _amount); -### Deserialize Data + // Format message body + bytes memory _burnMessage = BurnMessage._formatMessage( + messageBodyVersion, + Message.addressToBytes32(_burnToken), + _mintRecipient, + _amount, + Message.addressToBytes32(msg.sender) + ); -Deserialization is the reverse of serialization. Given a serialized `Uint8Array`, we can convert it back into its original structure using the `deserializeLayout` function. + uint64 _nonceReserved = _sendDepositForBurnMessage( + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller, + _burnMessage + ); -```typescript -const deserializedPayload = deserializeLayout(exampleLayout, serializedData); -``` + emit DepositForBurn( + _nonceReserved, + _burnToken, + _amount, + msg.sender, + _mintRecipient, + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller + ); -This will output the structured object, making it easy to work with data transmitted or received from another chain. + return _nonceReserved; + } -### Handling Variable-Length Fields + /** + * @notice Sends a BurnMessage through the local message transmitter + * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0), + * or else calls sendMessageWithCaller(). + * @param _destinationDomain destination domain + * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32 + * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0), + * any address can call receiveMessage() on destination domain. + * @param _burnMessage formatted BurnMessage bytes (message body) + * @return nonce unique nonce reserved by message + */ + function _sendDepositForBurnMessage( + uint32 _destinationDomain, + bytes32 _destinationTokenMessenger, + bytes32 _destinationCaller, + bytes memory _burnMessage + ) internal returns (uint64 nonce) { + if (_destinationCaller == bytes32(0)) { + return + localMessageTransmitter.sendMessage( + _destinationDomain, + _destinationTokenMessenger, + _burnMessage + ); + } else { + return + localMessageTransmitter.sendMessageWithCaller( + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller, + _burnMessage + ); + } + } -One relevant aspect of Wormhole SDK's layout system is the ability to handle variable-length fields, such as arrays and length-prefixed byte sequences. + /** + * @notice Mints tokens to a recipient + * @param _tokenMinter address of TokenMinter contract + * @param _remoteDomain domain where burned tokens originate from + * @param _burnToken address of token burned + * @param _mintRecipient recipient address of minted tokens + * @param _amount amount of minted tokens + */ + function _mintAndWithdraw( + address _tokenMinter, + uint32 _remoteDomain, + bytes32 _burnToken, + address _mintRecipient, + uint256 _amount + ) internal { + ITokenMinter _minter = ITokenMinter(_tokenMinter); + address _mintToken = _minter.mint( + _remoteDomain, + _burnToken, + _mintRecipient, + _amount + ); -For instance, if you want to serialize or deserialize a message where the length of the content isn't known beforehand, you can define a layout item with a `lengthSize` field. + emit MintAndWithdraw(_mintRecipient, _amount, _mintToken); + } -```typescript -{ name: 'message', binary: 'bytes', lengthSize: 4 } -``` + /** + * @notice return the remote TokenMessenger for the given `_domain` if one exists, else revert. + * @param _domain The domain for which to get the remote TokenMessenger + * @return _tokenMessenger The address of the TokenMessenger on `_domain` as bytes32 + */ + function _getRemoteTokenMessenger(uint32 _domain) + internal + view + returns (bytes32) + { + bytes32 _tokenMessenger = remoteTokenMessengers[_domain]; + require(_tokenMessenger != bytes32(0), "No TokenMessenger for domain"); + return _tokenMessenger; + } -This tells the SDK to read or write the message's length (in 4 bytes) and then handle the content. + /** + * @notice return the local minter address if it is set, else revert. + * @return local minter as ITokenMinter. + */ + function _getLocalMinter() internal view returns (ITokenMinter) { + require(address(localMinter) != address(0), "Local minter is not set"); + return localMinter; + } -## Nested Layouts and Strong Typing + /** + * @notice Return true if the given remote domain and TokenMessenger is registered + * on this TokenMessenger. + * @param _domain The remote domain of the message. + * @param _tokenMessenger The address of the TokenMessenger on remote domain. + * @return true if a remote TokenMessenger is registered for `_domain` and `_tokenMessenger`, + * on this TokenMessenger. + */ + function _isRemoteTokenMessenger(uint32 _domain, bytes32 _tokenMessenger) + internal + view + returns (bool) + { + return + _tokenMessenger != bytes32(0) && + remoteTokenMessengers[_domain] == _tokenMessenger; + } -The Wormhole SDK simplifies handling complex structures with nested layouts and strong typing. Nested layouts clearly represent hierarchical data, while strong typing ensures data consistency and catches errors during development. + /** + * @notice Returns true if the message sender is the local registered MessageTransmitter + * @return true if message sender is the registered local message transmitter + */ + function _isLocalMessageTransmitter() internal view returns (bool) { + return + address(localMessageTransmitter) != address(0) && + msg.sender == address(localMessageTransmitter); + } +} + ``` -### Nested Layout + This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol){target=\_blank} on GitHub. -In complex protocols, layouts can contain nested structures. Nested layouts become relevant here, allowing you to represent hierarchical data (such as transactions or multi-part messages) in a structured format. +The functions provided by the Token Messenger contract are as follows: -Refer to the following nested layout where a message contains nested fields: +- **`depositForBurn`** - deposits and burns tokens from the sender to be minted on the destination domain. Minted tokens will be transferred to `mintRecipient` -```typescript -const nestedLayout = [ - { - name: 'source', - binary: 'bytes', - layout: [ - { name: 'chainId', binary: 'uint', size: 2 }, - { name: 'sender', binary: 'bytes', size: 32 }, - ], - }, - { - name: 'redeemer', - binary: 'bytes', - layout: [ - { name: 'address', binary: 'bytes', size: 32 }, - { name: 'message', binary: 'bytes', lengthSize: 4 }, - ], - }, -] as const satisfies Layout; -``` + ??? interface "Parameters" -In this layout: + `amount` ++"uint256"++ + + The amount of tokens to burn. - - `source` is an object with two fields: `chainId` and `sender` - - `redeemer` is another object with two fields: `address` and a length-prefixed `message` + --- -### Strong Typing + `destinationDomain` ++"uint32"++ + + The network where the token will be minted after burn. + + --- + + `mintRecipient` ++"bytes32"++ + + Address of mint recipient on destination domain. -One of the benefits of using the Wormhole SDK in TypeScript is its support for strong typing. This ensures that serialized and deserialized data conform to expected structures, reducing errors during development by enforcing type checks at compile time. + --- -Using TypeScript, the `LayoutToType` utility provided by the SDK automatically generates a strongly typed structure based on the layout: + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -```typescript -type NestedMessage = LayoutToType; -``` + ??? interface "Returns" -This ensures that when you serialize or deserialize data, it matches the expected structure. + `_nonce` ++"uint64"++ + + Unique nonce reserved by message. -```typescript -const message: NestedMessage = { - source: { - chainId: 6, - sender: new Uint8Array(32), - }, - redeemer: { - address: new Uint8Array(32), - message: new Uint8Array([0x01, 0x02, 0x03]), - }, -}; -``` + ??? interface "Emits" -Attempting to assign data of incorrect types will result in a compile-time error. The Wormhole SDK's layout system enforces strong types, reducing runtime errors and improving code reliability. + `DepositForBurn` - event emitted when `depositForBurn` is called. The `destinationCaller` is set to `bytes32(0)` to allow any address to call `receiveMessage` on the destination domain -### Serialization and Deserialization with Nested Layouts + ??? child "Event Arguments" -You can serialize and deserialize nested structures in the same way as simpler layouts: + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -```typescript -const serializedNested = serializeLayout(nestedLayout, message); -const deserializedNested = deserializeLayout(nestedLayout, serializedNested); -``` + --- -Strong typing in TypeScript ensures that the message object conforms to the nested layout structure. This reduces the risk of data inconsistency during cross-chain communication. + `burnToken` ++"address"++ + + Address of token burnt on source domain. -## Commonly Used Layouts + --- -The Wormhole SDK includes predefined layouts frequently used in cross-chain messaging. These layouts are optimized for standard fields such as chain IDs, addresses, and signatures. You can explore the complete set of predefined layouts in the [`layout-items` directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/layout-items){target=\_blank} of the Wormhole SDK. + `amount` ++"uint256"++ + + The deposit amount. -### Chain ID Layouts + --- -Chain ID layouts in the Wormhole SDK derive from a common foundation: `chainItemBase`. This structure defines the binary representation of a chain ID as a 2-byte unsigned integer, ensuring consistency across serialization and deserialization processes. + `depositor` ++"address"++ + + Address where deposit is transferred from. -#### Base Structure + --- -This simple structure is the blueprint for more specific layouts by standardizing the binary format and size. + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. -```typescript -const chainItemBase = { binary: 'uint', size: 2 } as const; -``` + --- -#### Dynamic Chain ID Layout + `destinationDomain` ++"uint32"++ - + + Destination domain. -The dynamic chain ID layout, [`chainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L13-L40){target=\_blank}, extends `chainItemBase` by adding flexible custom conversion logic. It enables runtime validation of chain IDs, supports optional null values, and restricts chain IDs to a predefined set when needed. + --- -```typescript -export const chainItem = < - const C extends readonly Chain[] = typeof chains, - const N extends boolean = false, ->(opts?: { - allowedChains?: C; - allowNull?: N; -}) => - ({ - ...chainItemBase, // Builds on the base structure - custom: { - to: (val: number): AllowNull => { ... }, - from: (val: AllowNull): number => { ... }, - }, - }); -``` + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- -This layout is versatile. It allows the serialization of human-readable chain names (e.g., `Ethereum`) to numeric IDs (e.g., `1`) and vice versa. This is particularly useful when working with dynamic configurations or protocols supporting multiple chains. + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. -#### Fixed Chain ID Layout +- **`depositForBurnWithCaller`** - deposits and burns tokens from the sender to be minted on the destination domain. This method differs from `depositForBurn` in that the mint on the destination domain can only be called by the designated `destinationCaller` address -The fixed chain ID layout, [`fixedChainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L42-L49){target=\_blank}, is more rigid. It also extends `chainItemBase`, but the custom field is hardcoded for a single chain. This eliminates runtime validation and enforces strict adherence to a specific chain. + ??? interface "Parameters" -```typescript -export const fixedChainItem = (chain: C) => ({ - ...chainItemBase, // Builds on the base structure - custom: { - to: chain, - from: chainToChainId(chain), - }, -}); - -``` + `amount` ++"uint256"++ + + The amount of tokens to burn. -This layout allows developers to efficiently serialize and deserialize messages involving a single, fixed chain ID. + --- -### Address Layout + `destinationDomain` ++"uint32"++ + + The network where the token will be minted after burn. -The Wormhole SDK uses a Universal Address Layout to serialize and deserialize blockchain addresses into a standardized format. This layout ensures that addresses are always represented as fixed 32-byte binary values, enabling seamless cross-chain communication. + --- -#### Base Structure + `mintRecipient` ++"bytes32"++ + + Address of mint recipient on destination domain. -The [`universalAddressItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/universalAddress.ts#L7-L14){target=\_blank} defines the layout for addresses. It uses the binary type bytes and enforces a fixed size of 32 bytes for consistency. + --- -```typescript -export const universalAddressItem = { - binary: 'bytes', - size: 32, - custom: { - to: (val: Uint8Array): UniversalAddress => new UniversalAddress(val), - from: (val: UniversalAddress): Uint8Array => val.toUint8Array(), - } satisfies CustomConversion, -} as const satisfies LayoutItem; - -``` + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -This layout ensures consistent address handling by defining the following: + --- - - **Serialization** - converts a high-level `UniversalAddress` object into raw binary (32 bytes) for efficient storage or transmission - - **Deserialization** - converts raw binary back into a `UniversalAddress` object, enabling further interaction in a human-readable or programmatic format + `destinationCaller` ++"bytes32"++ + + Address of the caller on the destination domain who will trigger the mint. -### Signature Layout + ??? interface "Returns" -In the Wormhole SDK, the Signature Layout defines how to serialize and deserialize cryptographic signatures. These signatures verify message authenticity and ensure data integrity, particularly in Guardian-signed VAAs. + `_nonce` ++"uint64"++ + + Unique nonce reserved by message. -#### Base Structure + ??? interface "Emits" -The `signatureLayout` specifies the binary structure of a secp256k1 signature. It divides the signature into three components: + `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called -```typescript -const signatureLayout = [ - { name: 'r', binary: 'uint', size: 32 }, - { name: 's', binary: 'uint', size: 32 }, - { name: 'v', binary: 'uint', size: 1 }, -] as const satisfies Layout; -``` + ??? child "Event Arguments" -This layout provides a clear binary format for the secp256k1 signature, making it efficient to process within the Wormhole protocol. + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -#### Layout with Custom Conversion + --- -The [`signatureItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/signature.ts#L15-L22){target=\_blank} builds upon the `signatureLayout` by adding custom conversion logic. This conversion transforms raw binary data into a high-level `Signature` object and vice versa. + `burnToken` ++"address"++ + + Address of token burnt on source domain. -```typescript -export const signatureItem = { - binary: 'bytes', - layout: signatureLayout, - custom: { - to: (val: LayoutToType) => - new Signature(val.r, val.s, val.v), - from: (val: Signature) => ({ r: val.r, s: val.s, v: val.v }), - } satisfies CustomConversion, Signature>, -} as const satisfies BytesLayoutItem; - -``` + --- -The `custom` field ensures seamless integration of raw binary data with the `Signature` class, encapsulating signature-specific logic. + `amount` ++"uint256"++ + + The deposit amount. -## Advanced Use Cases + --- -The Wormhole SDK’s layout system is designed to handle various data structures and serialization needs. This section will explore more advanced use cases, such as handling conditional data structures, fixed conversions, and optimizing serialization performance. + `depositor` ++"address"++ + + Address where deposit is transferred from. -???- code "Switch Statements for Conditional Layouts" + --- - In some cases, the structure of serialized data might change based on a specific field, such as a payload ID. The switch layout type conditionally defines layouts based on a value. + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. - For example, different message types can be identified using a payload ID, and the layout for each message can be determined at runtime: + --- - ```typescript - const switchLayout = { - binary: 'switch', - idSize: 1, // size of the payload ID - idTag: 'messageType', // tag to identify the type of message - layouts: [ - [[1, 'messageType1'], fillLayout], // layout for type 1 - [[2, 'messageType2'], fastFillLayout], // layout for type 2 - ], -} as const satisfies Layout; - ``` + `destinationDomain` ++"uint32"++ - + + Destination domain. - The switch statement helps developers parse multiple payload types using the same structure, depending on a control field like an ID. + --- -???- code "Fixed Conversions and Omitted Fields" + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- - Fixed conversions and omitted fields allow developers to handle known, static data without including it in every serialization or deserialization operation. For instance, when specific fields in a layout always hold a constant value, they can be omitted from the deserialized object. + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. - **Example: Fixed Conversion** +- **`replaceDepositForBurn`** — replaces a previous `BurnMessage` to modify the mint recipient and/or the destination caller. The replacement message reuses the `_nonce` created by the original message, which allows the original message's sender to update the details without requiring a new deposit - In some cases, a field may always contain a predefined value. The layout system supports fixed conversions, allowing developers to “hard-code” these values: + ??? interface "Parameters" - ```typescript - const fixedConversionLayout = { - binary: 'uint', - size: 2, - custom: { - to: 'Ethereum', - from: chainToChainId('Ethereum'), - }, -} as const satisfies Layout; - ``` + `originalMessage` ++"bytes"++ + + The original burn message to be replaced. - **Example: Omitted Fields** + --- - Omitted fields are useful for handling padding or reserved fields that do not carry meaningful information and can safely be excluded from the deserialized output: + `originalAttestation` ++"bytes"++ + + The attestation of the original message. - ```typescript - const omittedFieldLayout = [ - { name: 'reserved', binary: 'uint', size: 2, omit: true }, -] as const satisfies Layout; - ``` + --- - In this example, `reserved` is a padding field with a fixed, non-dynamic value that serves no functional purpose. It is omitted from the deserialized result but still considered during serialization to maintain the correct binary format. + `newDestinationCaller` ++"bytes32"++ + + The new caller on the destination domain, can be the same or updated. - Only fields with a fixed, known value, such as padding or reserved fields, should be marked as `omit: true`. Fields with meaningful or dynamic information, such as `sourceChain` or `version`, must remain in the deserialized structure to ensure data integrity and allow seamless round-trip conversions between serialized and deserialized representations. + --- -## Integration with Wormhole Protocol + `newMintRecipient` ++"bytes32"++ + + The new recipient for the minted tokens, can be the same or updated. -The layout system facilitates seamless interaction with the Wormhole protocol, mainly when dealing with VAAs. These cross-chain messages must be serialized and deserialized to ensure they can be transmitted and processed accurately across different chains. + ??? interface "Returns" -### VAAs and Layouts + None. -VAAs are the backbone of Wormhole’s cross-chain communication. Each VAA is a signed message encapsulating important information such as the originating chain, the emitter address, a sequence number, and Guardian signatures. The Wormhole SDK leverages its layout system to define, serialize, and deserialize VAAs, ensuring data integrity and chain compatibility. + ??? interface "Emits" -#### Base VAA Structure + `DepositForBurn` - event emitted when `replaceDepositForBurn` is called. Note that the `destinationCaller` will reflect the new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid -The Wormhole SDK organizes the VAA structure into three key components: + ??? child "Event Arguments" - - [**Header**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L37-L41){target=\_blank} - contains metadata such as the Guardian set index and an array of Guardian signatures - - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} - - **Payload** - provides application-specific data, such as the actual message or operation being performed + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -**Header layout:** + --- -```typescript -const guardianSignatureLayout = [ - { name: 'guardianIndex', binary: 'uint', size: 1 }, - { name: 'signature', ...signatureItem }, -] as const satisfies Layout; + `burnToken` ++"address"++ + + Address of token burnt on source domain. -export const headerLayout = [ - { name: 'version', binary: 'uint', size: 1, custom: 1, omit: true }, - { name: 'guardianSet', ...guardianSetItem }, - { - name: 'signatures', - binary: 'array', - lengthSize: 1, - layout: guardianSignatureLayout, - }, -] as const satisfies Layout; -``` + --- -The header defines metadata for validating and processing the VAA, such as the Guardian set index and signatures. Each signature is represented using the `signatureItem` layout, ensuring consistency and compatibility across different platforms. + `amount` ++"uint256"++ + + The deposit amount. -!!! note "Signature Standard Compliance" + --- - The signature field uses the `signatureItem` layout, which is explicitly defined as 65 bytes. This layout is aligned with widely used standards such as EIP-2612 and Uniswap's Permit2, ensuring compatibility with cryptographic protocols and applications. + `depositor` ++"address"++ + + Address where deposit is transferred from. -**Envelope layout:** + --- -```typescript -export const envelopeLayout = [ - { name: 'timestamp', binary: 'uint', size: 4 }, - { name: 'nonce', binary: 'uint', size: 4 }, - { name: 'emitterChain', ...chainItem() }, - { name: 'emitterAddress', ...universalAddressItem }, - { name: 'sequence', ...sequenceItem }, - { name: 'consistencyLevel', binary: 'uint', size: 1 }, -] as const satisfies Layout; -``` + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. -The envelope encapsulates the VAA's core message data, including chain-specific information like the emitter address and sequence number. This structured layout ensures that the VAA can be securely transmitted across chains. + --- -**Payload Layout:** + `destinationDomain` ++"uint32"++ - + + Destination domain. -The Payload contains the user-defined data specific to the application or protocol, such as a token transfer message, governance action, or other cross-chain operation. The layout of the payload is dynamic and depends on the payload type, identified by the `payloadLiteral` field. + --- -```typescript -const examplePayloadLayout = [ - { name: 'type', binary: 'uint', size: 1 }, - { name: 'data', binary: 'bytes', lengthSize: 2 }, -] as const satisfies Layout; -``` + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- -This example demonstrates a payload containing: + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. - - A type field specifying the operation type (e.g., transfer or governance action) - - A data field that is length-prefixed and can store operation-specific information +- **`handleReceiveMessage`** - handles an incoming message received by the local `MessageTransmitter` and takes the appropriate action. For a burn message, it mints the associated token to the requested recipient on the local domain. -Dynamic payload layouts are selected at runtime using the `payloadLiteral` field, which maps to a predefined layout in the Wormhole SDK. + ???+ note -**Combined Base Layout:** + Though this function can only be called by the local `MessageTransmitter`, it is included here as it emits the essential event for minting tokens and withdrawing to send to the recipient. -The base VAA layout combines the header, envelope, and dynamically selected payload layout: + ??? interface "Parameters" -```typescript -export const baseLayout = [...headerLayout, ...envelopeLayout] as const; -``` + `remoteDomain` ++"uint32"++ + + The domain where the message originated. -At runtime, the payload layout is appended to the `baseLayout` to form the complete structure. + --- -#### Serializing VAA Data + `sender` ++"bytes32"++ + + The address of the sender of the message. -The Wormhole SDK provides the [`serialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L48-L54){target=\_blank} function to serialize a VAA message. This function combines the base layout (header and envelope) with the appropriate payload layout, ensuring the message’s format is correct for transmission across chains. + --- -```typescript -import { serialize } from '@wormhole-foundation/sdk-core/vaa/functions'; + `messageBody` ++"bytes"++ + + The bytes making up the body of the message. -const vaaData = { - guardianSet: 1, - signatures: [{ guardianIndex: 0, signature: new Uint8Array(65).fill(0) }], - timestamp: 1633000000, - nonce: 42, - emitterChain: 2, // Ethereum - emitterAddress: new Uint8Array(32).fill(0), - sequence: BigInt(1), - consistencyLevel: 1, - payloadLiteral: 'SomePayloadType', - payload: { key: 'value' }, -}; + ??? interface "Returns" -const serializedVAA = serialize(vaaData); -``` + `success` ++"boolean"++ + + Returns `true` if successful, otherwise, it returns `false`. -???- note "How does it work?" + ??? interface "Emits" - Internally, the serialize function dynamically combines the `baseLayout` (header and envelope) with the payload layout defined by the `payloadLiteral`. The complete layout is then passed to the `serializeLayout` function, which converts the data into binary format. + `MintAndWithdraw` - event emitted when tokens are minted - ```typescript - const layout = [ - ...baseLayout, // Header and envelope layout - payloadLiteralToPayloadItemLayout(vaa.payloadLiteral), // Payload layout -] as const; + ??? child "Event arguments" -return serializeLayout(layout, vaa as LayoutToType); - - ``` + `localMinter` ++"address"++ + + Minter responsible for minting and burning tokens on the local domain. -#### Deserializing VAA Data + --- -The Wormhole SDK provides the [`deserialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L162-L200){target=\_blank} function to parse a VAA from its binary format back into a structured object. This function uses the `baseLayout` and payload discriminator logic to ensure the VAA is correctly interpreted. + `remoteDomain` ++"uint32"++ + + The domain where the message originated from. -```typescript -import { deserialize } from '@wormhole-foundation/sdk-core/vaa/functions'; + --- -const serializedVAA = new Uint8Array([ - /* Serialized VAA binary data */ -]); + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -const vaaPayloadType = 'SomePayloadType'; // The payload type expected for this VAA -const deserializedVAA = deserialize(vaaPayloadType, serializedVAA); -``` + --- -???- note "How does it work?" + `mintRecipient` ++"address"++ + + Recipient address of minted tokens (indexed). - Internally, the `deserialize` function uses the `baseLayout` (header and envelope) to parse the main VAA structure. It then identifies the appropriate payload layout using the provided payload type or discriminator. + --- - ```typescript - const [header, envelopeOffset] = deserializeLayout(headerLayout, data, { - consumeAll: false, -}); + `amount` ++"uint256"++ + + Amount of minted tokens. -const [envelope, payloadOffset] = deserializeLayout(envelopeLayout, data, { - offset: envelopeOffset, - consumeAll: false, -}); +### Message Transmitter Contract -const [payloadLiteral, payload] = - typeof payloadDet === 'string' - ? [ - payloadDet as PayloadLiteral, - deserializePayload(payloadDet as PayloadLiteral, data, payloadOffset), - ] - : deserializePayload( - payloadDet as PayloadDiscriminator, - data, - payloadOffset - ); +The Message Transmitter contract ensures secure messaging across blockchain domains by managing message dispatch and tracking communication with events like `MessageSent` and `MessageReceived`. It uses a unique nonce for each message, which ensures proper validation, verifies attestation signatures, and prevents replay attacks. -return { - ...header, - ...envelope, - payloadLiteral, - payload, -} satisfies VAA; - ``` +The contract supports flexible delivery options, allowing messages to be sent to a specific `destinationCaller` or broadcast more generally. It also includes domain-specific configurations to manage communication between chains. -### Registering Custom Payloads +Additional features include replacing previously sent messages, setting maximum message body sizes, and verifying that messages are received only once per nonce to maintain network integrity. -In the Wormhole SDK, payloads rely on layouts to define their binary structure, ensuring consistency and type safety across protocols. Custom payloads extend this functionality, allowing developers to handle protocol-specific features or unique use cases. +??? code "Message Transmitter contract" + ```solidity + /* + * Copyright (c) 2022, Circle Internet Financial Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +pragma solidity 0.7.6; -To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} page for a detailed guide. +import "@memview-sol/contracts/TypedMemView.sol"; +import "./interfaces/IMessageTransmitter.sol"; +import "./interfaces/IMessageHandler.sol"; +import "./messages/Message.sol"; +import "./roles/Pausable.sol"; +import "./roles/Rescuable.sol"; +import "./roles/Attestable.sol"; -## Common Pitfalls & Best Practices +/** + * @title MessageTransmitter + * @notice Contract responsible for sending and receiving messages across chains. + */ +contract MessageTransmitter is + IMessageTransmitter, + Pausable, + Rescuable, + Attestable +{ + // ============ Events ============ + /** + * @notice Emitted when a new message is dispatched + * @param message Raw bytes of message + */ + event MessageSent(bytes message); -When working with the Wormhole SDK layout system, it's important to be aware of a few common issues that can arise. Below are some pitfalls to avoid and best practices to ensure smooth integration. + /** + * @notice Emitted when a new message is received + * @param caller Caller (msg.sender) on destination domain + * @param sourceDomain The source domain this message originated from + * @param nonce The nonce unique to this message + * @param sender The sender of this message + * @param messageBody message body bytes + */ + event MessageReceived( + address indexed caller, + uint32 sourceDomain, + uint64 indexed nonce, + bytes32 sender, + bytes messageBody + ); -### Pitfalls to Avoid + /** + * @notice Emitted when max message body size is updated + * @param newMaxMessageBodySize new maximum message body size, in bytes + */ + event MaxMessageBodySizeUpdated(uint256 newMaxMessageBodySize); -#### Defining Sizes for Data Types + // ============ Libraries ============ + using TypedMemView for bytes; + using TypedMemView for bytes29; + using Message for bytes29; -When defining sizes for each data type, make sure to match the actual data length to the specified size to prevent serialization and deserialization errors: + // ============ State Variables ============ + // Domain of chain on which the contract is deployed + uint32 public immutable localDomain; - - **`uint` and `int`** - the specified size must be large enough to accommodate the data value. For instance, storing a value greater than 255 in a single byte (`uint8`) will fail since it exceeds the byte’s capacity. Similarly, an undersized integer (e.g., specifying 2 bytes for a 4-byte integer) can lead to data loss or deserialization failure - - **`bytes`** - the data must match the specified byte length in the layout. For example, defining a field as 32 bytes (`size: 32`) requires the provided data to be exactly 32 bytes long; otherwise, serialization will fail + // Message Format version + uint32 public immutable version; -```typescript -// Pitfall: Mismatch between the size of data and the defined size in the layout -{ name: 'orderSender', binary: 'bytes', size: 32 } -// If the provided data is not exactly 32 bytes, this will fail -``` + // Maximum size of message body, in bytes. + // This value is set by owner. + uint256 public maxMessageBodySize; -#### Incorrectly Defined Arrays + // Next available nonce from this source domain + uint64 public nextAvailableNonce; -Arrays can be fixed-length or length-prefixed, so it’s important to define them correctly. Fixed-length arrays must match the specified length, while length-prefixed arrays need a `lengthSize` field. + // Maps a bytes32 hash of (sourceDomain, nonce) -> uint256 (0 if unused, 1 if used) + mapping(bytes32 => uint256) public usedNonces; -```typescript -// Pitfall: Array length does not match the expected size -{ name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 } -``` + // ============ Constructor ============ + constructor( + uint32 _localDomain, + address _attester, + uint32 _maxMessageBodySize, + uint32 _version + ) Attestable(_attester) { + localDomain = _localDomain; + maxMessageBodySize = _maxMessageBodySize; + version = _version; + } -### Best Practices + // ============ External Functions ============ + /** + * @notice Send the message to the destination domain and recipient + * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. + * @param destinationDomain Domain of destination chain + * @param recipient Address of message recipient on destination chain as bytes32 + * @param messageBody Raw bytes content of message + * @return nonce reserved by message + */ + function sendMessage( + uint32 destinationDomain, + bytes32 recipient, + bytes calldata messageBody + ) external override whenNotPaused returns (uint64) { + bytes32 _emptyDestinationCaller = bytes32(0); + uint64 _nonce = _reserveAndIncrementNonce(); + bytes32 _messageSender = Message.addressToBytes32(msg.sender); -These best practices and common pitfalls can help prevent bugs and improve the reliability of your implementation when working with layouts in the Wormhole SDK. + _sendMessage( + destinationDomain, + recipient, + _emptyDestinationCaller, + _messageSender, + _nonce, + messageBody + ); -#### Reuse Predefined Layout Items + return _nonce; + } -Rather than defining sizes or types manually, reuse the predefined layout items provided by the Wormhole SDK. These items ensure consistent formatting and enforce strong typing. + /** + * @notice Replace a message with a new message body and/or destination caller. + * @dev The `originalAttestation` must be a valid attestation of `originalMessage`. + * Reverts if msg.sender does not match sender of original message, or if the source domain of the original message + * does not match this MessageTransmitter's local domain. + * @param originalMessage original message to replace + * @param originalAttestation attestation of `originalMessage` + * @param newMessageBody new message body of replaced message + * @param newDestinationCaller the new destination caller, which may be the + * same as the original destination caller, a new destination caller, or an empty + * destination caller (bytes32(0), indicating that any destination caller is valid.) + */ + function replaceMessage( + bytes calldata originalMessage, + bytes calldata originalAttestation, + bytes calldata newMessageBody, + bytes32 newDestinationCaller + ) external override whenNotPaused { + // Validate each signature in the attestation + _verifyAttestationSignatures(originalMessage, originalAttestation); -For instance, use the `chainItem` layout for chain IDs or `universalAddressItem` for blockchain addresses: + bytes29 _originalMsg = originalMessage.ref(0); -```typescript -import { - chainItem, - universalAddressItem, -} from '@wormhole-foundation/sdk-core/layout-items'; + // Validate message format + _originalMsg._validateMessageFormat(); -const exampleLayout = [ - { name: 'sourceChain', ...chainItem() }, // Use predefined chain ID layout - { name: 'senderAddress', ...universalAddressItem }, // Use universal address layout -] as const; -``` + // Validate message sender + bytes32 _sender = _originalMsg._sender(); + require( + msg.sender == Message.bytes32ToAddress(_sender), + "Sender not permitted to use nonce" + ); -By leveraging predefined layout items, you reduce redundancy, maintain consistency, and ensure compatibility with Wormhole’s standards. + // Validate source domain + uint32 _sourceDomain = _originalMsg._sourceDomain(); + require( + _sourceDomain == localDomain, + "Message not originally sent from this domain" + ); -#### Use Class Instances + uint32 _destinationDomain = _originalMsg._destinationDomain(); + bytes32 _recipient = _originalMsg._recipient(); + uint64 _nonce = _originalMsg._nonce(); -Whenever possible, convert deserialized data into higher-level class instances. This makes it easier to validate, manipulate, and interact with structured data. For example, the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/universalAddress.ts#L17-L59){target=\_blank} class ensures consistent address handling: + _sendMessage( + _destinationDomain, + _recipient, + newDestinationCaller, + _sender, + _nonce, + newMessageBody + ); + } -```typescript -import { UniversalAddress } from '@wormhole-foundation/sdk-core'; + /** + * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the + * destination domain. + * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. + * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible + * to broadcast the message on the destination domain. This is an advanced feature, and the standard + * sendMessage() should be preferred for use cases where a specific destination caller is not required. + * @param destinationDomain Domain of destination chain + * @param recipient Address of message recipient on destination domain as bytes32 + * @param destinationCaller caller on the destination domain, as bytes32 + * @param messageBody Raw bytes content of message + * @return nonce reserved by message + */ + function sendMessageWithCaller( + uint32 destinationDomain, + bytes32 recipient, + bytes32 destinationCaller, + bytes calldata messageBody + ) external override whenNotPaused returns (uint64) { + require( + destinationCaller != bytes32(0), + "Destination caller must be nonzero" + ); -const deserializedAddress = new UniversalAddress(someBinaryData); -``` + uint64 _nonce = _reserveAndIncrementNonce(); + bytes32 _messageSender = Message.addressToBytes32(msg.sender); -Focusing on reusing predefined layout items and converting deserialized data into higher-level abstractions can ensure a more robust and maintainable implementation. + _sendMessage( + destinationDomain, + recipient, + destinationCaller, + _messageSender, + _nonce, + messageBody + ); -#### Consistent Error Handling + return _nonce; + } -Always handle errors during both serialization and deserialization. Catching exceptions allows you to log or resolve issues gracefully when working with potentially corrupted or invalid data. + /** + * @notice Receive a message. Messages with a given nonce + * can only be broadcast once for a (sourceDomain, destinationDomain) + * pair. The message body of a valid message is passed to the + * specified recipient for further processing. + * + * @dev Attestation format: + * A valid attestation is the concatenated 65-byte signature(s) of exactly + * `thresholdSignature` signatures, in increasing order of attester address. + * ***If the attester addresses recovered from signatures are not in + * increasing order, signature verification will fail.*** + * If incorrect number of signatures or duplicate signatures are supplied, + * signature verification will fail. + * + * Message format: + * Field Bytes Type Index + * version 4 uint32 0 + * sourceDomain 4 uint32 4 + * destinationDomain 4 uint32 8 + * nonce 8 uint64 12 + * sender 32 bytes32 20 + * recipient 32 bytes32 52 + * messageBody dynamic bytes 84 + * @param message Message bytes + * @param attestation Concatenated 65-byte signature(s) of `message`, in increasing order + * of the attester address recovered from signatures. + * @return success bool, true if successful + */ + function receiveMessage(bytes calldata message, bytes calldata attestation) + external + override + whenNotPaused + returns (bool success) + { + // Validate each signature in the attestation + _verifyAttestationSignatures(message, attestation); -```typescript -try { - const deserialized = deserializeLayout(fillLayout, data); -} catch (error) { - console.error('Deserialization failed:', error); -} -``` + bytes29 _msg = message.ref(0); -#### Leverage Reusable Layouts + // Validate message format + _msg._validateMessageFormat(); -Creating reusable layouts for commonly repeated structures improves code maintainability and reduces duplication. These layouts can represent fields or combinations of fields frequently encountered in cross-chain communication, such as chain IDs, addresses, and signatures. + // Validate domain + require( + _msg._destinationDomain() == localDomain, + "Invalid destination domain" + ); -For example, define a reusable layout for chain IDs and addresses: + // Validate destination caller + if (_msg._destinationCaller() != bytes32(0)) { + require( + _msg._destinationCaller() == + Message.addressToBytes32(msg.sender), + "Invalid caller for message" + ); + } -```typescript -const commonLayout = [ - { name: 'chainId', binary: 'uint', size: 2 }, - { name: 'address', binary: 'bytes', size: 32 }, -] as const satisfies Layout; + // Validate version + require(_msg._version() == version, "Invalid message version"); -// Reuse the common layout in different contexts -const exampleLayout = [ - ...commonLayout, - { name: 'sequence', binary: 'uint', size: 8 }, -]; -``` + // Validate nonce is available + uint32 _sourceDomain = _msg._sourceDomain(); + uint64 _nonce = _msg._nonce(); + bytes32 _sourceAndNonce = _hashSourceAndNonce(_sourceDomain, _nonce); + require(usedNonces[_sourceAndNonce] == 0, "Nonce already used"); + // Mark nonce used + usedNonces[_sourceAndNonce] = 1; -By abstracting common elements into a single layout, you ensure consistency across different parts of your application and simplify future updates. + // Handle receive message + bytes32 _sender = _msg._sender(); + bytes memory _messageBody = _msg._messageBody().clone(); + require( + IMessageHandler(Message.bytes32ToAddress(_msg._recipient())) + .handleReceiveMessage(_sourceDomain, _sender, _messageBody), + "handleReceiveMessage() failed" + ); -## Performance Considerations + // Emit MessageReceived event + emit MessageReceived( + msg.sender, + _sourceDomain, + _nonce, + _sender, + _messageBody + ); + return true; + } -Efficient serialization and deserialization are crucial when handling large amounts of cross-chain data. Below are some strategies and best practices to ensure optimal performance when using Wormhole SDK layouts. + /** + * @notice Sets the max message body size + * @dev This value should not be reduced without good reason, + * to avoid impacting users who rely on large messages. + * @param newMaxMessageBodySize new max message body size, in bytes + */ + function setMaxMessageBodySize(uint256 newMaxMessageBodySize) + external + onlyOwner + { + maxMessageBodySize = newMaxMessageBodySize; + emit MaxMessageBodySizeUpdated(maxMessageBodySize); + } -### Lazy Instantiation + // ============ Internal Utils ============ + /** + * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0), + * the message can only be received on the destination chain when called by `_destinationCaller`. + * @dev Format the message and emit `MessageSent` event with message information. + * @param _destinationDomain Domain of destination chain + * @param _recipient Address of message recipient on destination domain as bytes32 + * @param _destinationCaller caller on the destination domain, as bytes32 + * @param _sender message sender, as bytes32 + * @param _nonce nonce reserved for message + * @param _messageBody Raw bytes content of message + */ + function _sendMessage( + uint32 _destinationDomain, + bytes32 _recipient, + bytes32 _destinationCaller, + bytes32 _sender, + uint64 _nonce, + bytes calldata _messageBody + ) internal { + // Validate message body length + require( + _messageBody.length <= maxMessageBodySize, + "Message body exceeds max size" + ); -Building a discriminator can be resource-intensive for complex or large datasets. The layout structures do not incur significant upfront costs, but deferring the creation of discriminators until needed can improve efficiency. + require(_recipient != bytes32(0), "Recipient must be nonzero"); -```typescript -const lazyDiscriminator = lazyInstantiate(() => layoutDiscriminator(layouts)); -``` + // serialize message + bytes memory _message = Message._formatMessage( + version, + localDomain, + _destinationDomain, + _nonce, + _sender, + _recipient, + _destinationCaller, + _messageBody + ); -This approach ensures that discriminators are only built when required, helping to optimize performance, especially for complex or conditional layouts. + // Emit MessageSent event + emit MessageSent(_message); + } -## Resources + /** + * @notice hashes `_source` and `_nonce`. + * @param _source Domain of chain where the transfer originated + * @param _nonce The unique identifier for the message from source to + destination + * @return hash of source and nonce + */ + function _hashSourceAndNonce(uint32 _source, uint64 _nonce) + internal + pure + returns (bytes32) + { + return keccak256(abi.encodePacked(_source, _nonce)); + } -For further learning and practical experience, explore the following resources: + /** + * Reserve and increment next available nonce + * @return nonce reserved + */ + function _reserveAndIncrementNonce() internal returns (uint64) { + uint64 _nonceReserved = nextAvailableNonce; + nextAvailableNonce = nextAvailableNonce + 1; + return _nonceReserved; + } +} + ``` - - **Wormhole TypeScript SDK** - the [Wormhole SDK repository](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} contains the core implementation of layouts, including predefined layout items and utilities like `serializeLayout` and `deserializeLayout` + This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol){target=\_blank} on GitHub. - - **Layout tests repository** - for hands-on experimentation, check out this [layout package repository](https://github.com/nonergodic/layout){target=\_blank}, which provides examples and unit tests to help you better understand serialization, deserialization, and the strong typing mechanism. Running these tests locally is a great way to deepen your understanding of how layouts function in real-world scenarios ---- END CONTENT --- +The functions provided by the Message Transmitter contract are as follows: -Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/vaas-protocols/ ---- BEGIN CONTENT --- ---- -title: VAAs and Protocols -description: Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. -categories: Typescript-SDK ---- +- **`receiveMessage`** — processes and validates an incoming message and its attestation. If valid, it triggers further action based on the message body -# VAAs and Protocols + ??? interface "Parameters" -## Introduction + `message` ++"bytes"++ + + The message to be processed, including details such as sender, recipient, and message body. -Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. + --- -For deeper insights into serialization, deserialization, and protocol design, refer to: + `attestation` ++"bytes"++ + + Concatenated 65-byte signature(s) that attest to the validity of the `message`. -- [Data Layouts](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank} for serialization concepts -- [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} for designing custom protocol messages + ??? interface "Returns" -This guide will help you understand how to handle VAAs and protocol messages in off-chain and on-chain scenarios. + `success` ++"boolean"++ + + Returns `true` if successful, otherwise, returns `false`. -## VAA Structure + ??? interface "Emits" -Understanding the structure of VAAs is fundamental to working with Wormhole's SDKs. Each section of the VAA—Header, Envelope, and Payload—serves a specific role: + `MessageReceived` - event emitted when a new message is received -| Section | Description | -|----------|----------------------------------------------------------------------------------------------------------| -| Header | Includes the version and guardian signature information required to verify the VAA | -| Envelope | Contains metadata about the emitted message, such as the emitter chain, emitter address, and timestamp | -| Payload | Represents the actual message, in raw bytes, without a length prefix | + ??? child "Event arguments" -The VAA's body combines the Envelope and Payload. The Wormhole Guardians signed the core data and hashed (using `keccak256`) to generate the VAA's unique identifier. + `caller` ++"address"++ + + Caller on destination domain. -When integrating protocols like Token Bridge or Wormhole Relayer: + --- -- The TypeScript SDK handles VAAs off-chain, focusing on deserialization, validation, and payload extraction before submission -- The Solidity SDK processes VAAs on-chain, using libraries like `VaaLib` to decode and execute protocol actions + `sourceDomain` ++"uint32"++ + + The source domain this message originated from. -## VAAs in Protocol Contexts + --- -### How VAAs Enable Protocol-Specific Messaging + `nonce` ++"uint64"++ + + Nonce unique to this message (indexed). -VAAs are the backbone of Wormhole's cross-chain communication, encapsulating critical protocol payloads that drive actions on different blockchains. Each protocol—such as [Token Bridge](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/tokenBridge){target=\_blank}, [Wormhole Relayer](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/relayer){target=\_blank}, or [Circle CCTP](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/circleBridge){target=\_blank}—uses VAAs to securely transmit its messages across chains. + --- -Examples of mapping protocols to VAAs: + `sender` ++"bytes32"++ + + Sender of this message. -| Protocol | Payload Purpose | Example | -|-----------------|-----------------------------------------------------------|------------------------------------| -| Token Bridge | Transfers token data and metadata | Token transfer or redemption | -| Wormhole Relayer| Manages delivery instructions for messages across chains | Delivery fee or refund handling | -| Circle CCTP | Facilitates stablecoin mint-and-burn operations | Circle-issued stablecoin transfer | + --- -Each protocol integrates its payload format into the VAA structure, ensuring consistent message validation and execution across the ecosystem. + `messageBody` ++"bytes"++ + + The body of the message. -### TypeScript SDK: Off-Chain Handling of VAAs +- **`sendMessage`** — sends a message to the destination domain and recipient. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event -The TypeScript SDK is designed for off-chain operations like reading, validating, and manipulating VAAs before submitting them to a chain. Developers can easily deserialize VAAs to extract protocol payloads and prepare actions such as initiating token transfers or constructing delivery instructions. + ??? interface "Parameters" -In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank}: + `destinationDomain` ++"uint32"++ + + The target blockchain network where the message is to be sent. -```typescript -import { deserializeLayout } from '@wormhole-foundation/sdk-base'; -import { - universalAddressItem, - sequenceItem, -} from '@wormhole-foundation/core/layout-items/index.js'; + --- -export const envelopeLayout = [ - { name: 'timestamp', binary: 'uint', size: 4 }, - { name: 'nonce', binary: 'uint', size: 4 }, - { name: 'emitterChain', binary: 'uint', size: 2 }, - { name: 'emitterAddress', ...universalAddressItem }, - { name: 'sequence', ...sequenceItem }, - { name: 'consistencyLevel', binary: 'uint', size: 1 }, -] as const satisfies Layout; + `recipient` ++"bytes32"++ + + The recipient's address on the destination domain. -const encodedEnvelope = new Uint8Array([ - /* binary envelope data */ -]); -const deserializedEnvelope = deserializeLayout(envelopeLayout, encodedEnvelope); -``` + --- + + `messageBody` ++"bytes"++ + + The raw bytes content of the message. -For more details, you can refer to the [parseVAA example](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts){target=\_blank} in the Wormhole SDK repository. + ??? interface "Returns" -### Solidity SDK: On-Chain Handling of VAAs + `nonce` ++"uint64"++ + + Nonce unique to this message. -The Solidity SDK enables on-chain processing of VAAs directly within smart contracts. This is essential for real-time validation, decoding, and execution of protocol-specific payloads. Developers can use libraries like [`VaaLib`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/e19013d08d1fdf5af9e6344c637e36a270422dd9/src/libraries/VaaLib.sol){target=\_blank} to parse the VAA header and payload, ensuring the message is authentic and consistent with Wormhole's validation. + ??? interface "Emits" -Below is an example of parsing an envelope on-chain using the Solidity SDK: + `MessageSent` - event emitted when a new message is dispatched -```solidity -// SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; +??? child "Event arguments" -import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; + `message` ++"bytes"++ + + The raw bytes of the message. -contract EnvelopeParser { - using VaaLib for bytes; +- **`sendMessageWithCaller`** — sends a message to the destination domain and recipient, requiring a specific caller to trigger the message on the target chain. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event - function parseEnvelope( - bytes memory encodedVaa - ) - public - pure - returns ( - uint32 timestamp, - uint32 nonce, - uint16 emitterChainId, - bytes32 emitterAddress, - uint64 sequence, - uint8 consistencyLevel - ) - { - // Skip the header and decode the envelope - uint offset = VaaLib.skipVaaHeaderMemUnchecked(encodedVaa, 0); - return VaaLib.decodeVaaEnvelopeMemUnchecked(encodedVaa, offset); - } -} -``` ---- END CONTENT --- + ??? interface "Parameters" -Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/sdk-reference/ ---- BEGIN CONTENT --- ---- -title: Wormhole TS SDK -description: Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. -categories: Typescript-SDK ---- + `destinationDomain` ++"uint32"++ + + The target blockchain network where the message is to be sent. -# Wormhole TypeScript SDK + --- -## Introduction + `recipient` ++"bytes32"++ + + The recipient's address on the destination domain. -The Wormhole TypeScript SDK is useful for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole. This package bundles together functions, definitions, and constants that streamline the process of connecting chains and completing transfers using Wormhole. The SDK also offers targeted sub-packages for Wormhole-connected platforms, which allow you to add multichain support without creating outsized dependencies. + --- -This section covers all you need to know about the functionality and ease of development offered through the Wormhole TypeScript SDK. Take a tour of the package to discover how it helps make integration easier. Learn more about how the SDK abstracts away complexities around concepts like platforms, contexts, and signers. Finally, you'll find guidance on usage, along with code examples, to show you how to use the tools of the SDK. + `destinationCaller` ++"bytes32"++ + + The caller on the destination domain. + --- -
+ `messageBody` ++"bytes"++ + + The raw bytes content of the message. -- :octicons-download-16:{ .lg .middle } **Installation** + ??? interface "Returns" - --- + `nonce` ++"uint64"++ + + Nonce unique to this message. - Find installation instructions for both the meta package and installing specific, individual packages + ??? interface "Emits" - [:custom-arrow: Install the SDK](#installation) + `MessageSent` - event emitted when a new message is dispatched -- :octicons-book-16:{ .lg .middle } **Concepts** +??? child "Event arguments" - --- + `message` ++"bytes"++ + + The raw bytes of the message. - Understand key concepts and how the SDK abstracts them away. Learn more about platforms, chain context, addresses, and signers +- **`replaceMessage`** — replaces an original message with a new message body and/or updates the destination caller. The replacement message reuses the `_nonce` created by the original message - [:custom-arrow: Explore concepts](#concepts) + ??? interface "Parameters" -- :octicons-file-code-16:{ .lg .middle } **Usage** + `originalMessage` ++"bytes"++ + + The original message to be replaced. - --- + --- - Guidance on using the SDK to add seamless interchain messaging to your application, including code examples + `originalAttestation` ++"bytes"++ + + Attestation verifying the original message. - [:custom-arrow: Use the SDK](#usage) + --- -- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** + `newMessageBody` ++"bytes"++ + + The new content for the replaced message. - --- + --- - Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at availabel methods, classes, interfaces, and definitions + `newDestinationCaller` ++"bytes32"++ + + The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid. - [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} + ??? interface "Returns" -
+ None. -!!! warning - This package is a work in progress. The interface may change, and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} any issues you find. + ??? interface "Emits" -## Installation + `MessageSent` - event emitted when a new message is dispatched -### Basic +??? child "Event arguments" -To install the meta package using npm, run the following command in the root directory of your project: + `message` ++"bytes"++ + + The raw bytes of the message. -```bash -npm install @wormhole-foundation/sdk -``` +### Token Minter Contract -This package combines all the individual packages to make setup easier while allowing for tree shaking. +The Token Minter contract manages the minting and burning of tokens across different blockchain domains. It maintains a registry that links local tokens to their corresponding remote tokens, ensuring that tokens maintain a 1:1 exchange rate across domains. -### Advanced +The contract restricts minting and burning functions to a designated Token Messenger, which ensures secure and reliable cross-chain operations. When tokens are burned on a remote domain, an equivalent amount is minted on the local domain for a specified recipient, and vice versa. -Alternatively, you can install a specific set of published packages individually: +To enhance control and flexibility, the contract includes mechanisms to pause operations, set burn limits, and update the Token Controller, which governs token minting permissions. Additionally, it provides functionality to add or remove the local Token Messenger and retrieve the local token address associated with a remote token. -??? interface "`sdk-base` - exposes constants" +??? code "Token Minter contract" + ```solidity + /* + * Copyright (c) 2022, Circle Internet Financial Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +pragma solidity 0.7.6; - ```sh - npm install @wormhole-foundation/sdk-base - ``` +import "./interfaces/ITokenMinter.sol"; +import "./interfaces/IMintBurnToken.sol"; +import "./roles/Pausable.sol"; +import "./roles/Rescuable.sol"; +import "./roles/TokenController.sol"; +import "./TokenMessenger.sol"; -??? interface "`sdk-definitions` - exposes contract interfaces, basic types, and VAA payload definitions" +/** + * @title TokenMinter + * @notice Token Minter and Burner + * @dev Maintains registry of local mintable tokens and corresponding tokens on remote domains. + * This registry can be used by caller to determine which token on local domain to mint for a + * burned token on a remote domain, and vice versa. + * It is assumed that local and remote tokens are fungible at a constant 1:1 exchange rate. + */ +contract TokenMinter is ITokenMinter, TokenController, Pausable, Rescuable { + // ============ Events ============ + /** + * @notice Emitted when a local TokenMessenger is added + * @param localTokenMessenger address of local TokenMessenger + * @notice Emitted when a local TokenMessenger is added + */ + event LocalTokenMessengerAdded(address localTokenMessenger); - ```sh - npm install @wormhole-foundation/sdk-definitions - ``` + /** + * @notice Emitted when a local TokenMessenger is removed + * @param localTokenMessenger address of local TokenMessenger + * @notice Emitted when a local TokenMessenger is removed + */ + event LocalTokenMessengerRemoved(address localTokenMessenger); -??? interface "`sdk-evm` - exposes EVM-specific utilities" + // ============ State Variables ============ + // Local TokenMessenger with permission to call mint and burn on this TokenMinter + address public localTokenMessenger; - ```sh - npm install @wormhole-foundation/sdk-evm - ``` + // ============ Modifiers ============ + /** + * @notice Only accept messages from the registered message transmitter on local domain + */ + modifier onlyLocalTokenMessenger() { + require(_isLocalTokenMessenger(), "Caller not local TokenMessenger"); + _; + } -??? interface "`sdk-evm-tokenbridge` - exposes the EVM Token Bridge protocol client" + // ============ Constructor ============ + /** + * @param _tokenController Token controller address + */ + constructor(address _tokenController) { + _setTokenController(_tokenController); + } - ```sh - npm install @wormhole-foundation/sdk-evm-tokenbridge - ``` + // ============ External Functions ============ + /** + * @notice Mints `amount` of local tokens corresponding to the + * given (`sourceDomain`, `burnToken`) pair, to `to` address. + * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not + * map to a nonzero local token address. This mapping can be queried using + * getLocalToken(). + * @param sourceDomain Source domain where `burnToken` was burned. + * @param burnToken Burned token address as bytes32. + * @param to Address to receive minted tokens, corresponding to `burnToken`, + * on this domain. + * @param amount Amount of tokens to mint. Must be less than or equal + * to the minterAllowance of this TokenMinter for given `_mintToken`. + * @return mintToken token minted. + */ + function mint( + uint32 sourceDomain, + bytes32 burnToken, + address to, + uint256 amount + ) + external + override + whenNotPaused + onlyLocalTokenMessenger + returns (address mintToken) + { + address _mintToken = _getLocalToken(sourceDomain, burnToken); + require(_mintToken != address(0), "Mint token not supported"); + IMintBurnToken _token = IMintBurnToken(_mintToken); + + require(_token.mint(to, amount), "Mint operation failed"); + return _mintToken; + } + + /** + * @notice Burn tokens owned by this TokenMinter. + * @param burnToken burnable token address. + * @param burnAmount amount of tokens to burn. Must be + * > 0, and <= maximum burn amount per message. + */ + function burn(address burnToken, uint256 burnAmount) + external + override + whenNotPaused + onlyLocalTokenMessenger + onlyWithinBurnLimit(burnToken, burnAmount) + { + IMintBurnToken _token = IMintBurnToken(burnToken); + _token.burn(burnAmount); + } -## Usage + /** + * @notice Add TokenMessenger for the local domain. Only this TokenMessenger + * has permission to call mint() and burn() on this TokenMinter. + * @dev Reverts if a TokenMessenger is already set for the local domain. + * @param newLocalTokenMessenger The address of the new TokenMessenger on the local domain. + */ + function addLocalTokenMessenger(address newLocalTokenMessenger) + external + onlyOwner + { + require( + newLocalTokenMessenger != address(0), + "Invalid TokenMessenger address" + ); -Getting your integration started is simple. First, import Wormhole: + require( + localTokenMessenger == address(0), + "Local TokenMessenger already set" + ); -```ts -import { wormhole } from '@wormhole-foundation/sdk'; + localTokenMessenger = newLocalTokenMessenger; -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; + emit LocalTokenMessengerAdded(localTokenMessenger); + } -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); + /** + * @notice Remove the TokenMessenger for the local domain. + * @dev Reverts if the TokenMessenger of the local domain is not set. + */ + function removeLocalTokenMessenger() external onlyOwner { + address _localTokenMessengerBeforeRemoval = localTokenMessenger; + require( + _localTokenMessengerBeforeRemoval != address(0), + "No local TokenMessenger is set" + ); - const ctx = wh.getChain('Solana'); + delete localTokenMessenger; + emit LocalTokenMessengerRemoved(_localTokenMessengerBeforeRemoval); + } - const rcv = wh.getChain('Algorand'); + /** + * @notice Set tokenController to `newTokenController`, and + * emit `SetTokenController` event. + * @dev newTokenController must be nonzero. + * @param newTokenController address of new token controller + */ + function setTokenController(address newTokenController) + external + override + onlyOwner + { + _setTokenController(newTokenController); + } - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); + /** + * @notice Get the local token address associated with the given + * remote domain and token. + * @param remoteDomain Remote domain + * @param remoteToken Remote token + * @return local token address + */ + function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) + external + view + override + returns (address) + { + return _getLocalToken(remoteDomain, remoteToken); + } - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); + // ============ Internal Utils ============ + /** + * @notice Returns true if the message sender is the registered local TokenMessenger + * @return True if the message sender is the registered local TokenMessenger + */ + function _isLocalTokenMessenger() internal view returns (bool) { + return + address(localTokenMessenger) != address(0) && + msg.sender == address(localTokenMessenger); + } +} + ``` - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); + This contract and the interfaces and contracts it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMinter.sol){target=\_blank} on GitHub. - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); +Most of the methods of the Token Minter contract can be called only by the registered Token Messenger. However, there is one publicly accessible method, a public view function that allows anyone to query the local token associated with a remote domain and token. - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); +- **`getLocalToken`** — a read-only function that returns the local token address associated with a given remote domain and token - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); + ??? interface "Parameters" - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); + `remoteDomain` ++"uint32"++ + + The remote blockchain domain where the token resides. - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); + --- - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); + `remoteToken` ++"bytes32"++ + + The address of the token on the remote domain. - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); + ??? interface "Returns" - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); + ++"address"++ + + The local token address. - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); -``` +## How to Interact with CCTP Contracts -Then, import each of the ecosystem [platforms](#platforms) that you wish to support: +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole CCTP contracts. The primary functionality revolves around the following: -```ts -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -``` +- **Sending tokens with a message payload** - initiating a cross-chain transfer of Circle-supported assets along with a message payload to a specific target address on the target chain +- **Receiving tokens with a message payload** - validating messages received from other chains via Wormhole and then minting the tokens for the recipient +### Sending Tokens and Messages -To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: +To initiate a cross-chain transfer, you must call the `transferTokensWithPayload` method of Wormhole's Circle Integration (CCTP) contract. Once you have initiated a transfer, you must fetch the attested Wormhole message and parse the transaction logs to locate a transfer message emitted by the Circle Bridge contract. Then, a request must be sent to Circle's off-chain process with the transfer message to grab the attestation from the process's response, which validates the token mint on the target chain. -```ts -evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); -``` +To streamline this process, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank}, which exposes the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank}, including the [`CCTPSender` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. By inheriting this contract, you can transfer USDC while automatically relaying the message payload to the destination chain via a Wormhole-deployed relayer. -With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. +??? code "CCTP Sender contract" -```ts + ```solidity + abstract contract CCTPSender is CCTPBase { + uint8 internal constant CONSISTENCY_LEVEL_FINALIZED = 15; -``` + using CCTPMessageLib for *; -You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. + mapping(uint16 => uint32) public chainIdToCCTPDomain; -```ts -// Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); -``` + /** + * Sets the CCTP Domain corresponding to chain 'chain' to be 'cctpDomain' + * So that transfers of USDC to chain 'chain' use the target CCTP domain 'cctpDomain' + * + * This action can only be performed by 'cctpConfigurationOwner', who is set to be the deployer + * + * Currently, cctp domains are: + * Ethereum: Wormhole chain id 2, cctp domain 0 + * Avalanche: Wormhole chain id 6, cctp domain 1 + * Optimism: Wormhole chain id 24, cctp domain 2 + * Arbitrum: Wormhole chain id 23, cctp domain 3 + * Base: Wormhole chain id 30, cctp domain 6 + * + * These can be set via: + * setCCTPDomain(2, 0); + * setCCTPDomain(6, 1); + * setCCTPDomain(24, 2); + * setCCTPDomain(23, 3); + * setCCTPDomain(30, 6); + */ + function setCCTPDomain(uint16 chain, uint32 cctpDomain) public { + require( + msg.sender == cctpConfigurationOwner, + "Not allowed to set CCTP Domain" + ); + chainIdToCCTPDomain[chain] = cctpDomain; + } -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; + function getCCTPDomain(uint16 chain) internal view returns (uint32) { + return chainIdToCCTPDomain[chain]; + } -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; + /** + * transferUSDC wraps common boilerplate for sending tokens to another chain using IWormholeRelayer + * - approves the Circle TokenMessenger contract to spend 'amount' of USDC + * - calls Circle's 'depositForBurnWithCaller' + * - returns key for inclusion in WormholeRelayer `additionalVaas` argument + * + * Note: this requires that only the targetAddress can redeem transfers. + * + */ -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); + function transferUSDC( + uint256 amount, + uint16 targetChain, + address targetAddress + ) internal returns (MessageKey memory) { + IERC20(USDC).approve(address(circleTokenMessenger), amount); + bytes32 targetAddressBytes32 = addressToBytes32CCTP(targetAddress); + uint64 nonce = circleTokenMessenger.depositForBurnWithCaller( + amount, + getCCTPDomain(targetChain), + targetAddressBytes32, + USDC, + targetAddressBytes32 + ); + return + MessageKey( + CCTPMessageLib.CCTP_KEY_TYPE, + abi.encodePacked(getCCTPDomain(wormhole.chainId()), nonce) + ); + } - const ctx = wh.getChain('Solana'); + // Publishes a CCTP transfer of 'amount' of USDC + // and requests a delivery of the transfer along with 'payload' to 'targetAddress' on 'targetChain' + // + // The second step is done by publishing a wormhole message representing a request + // to call 'receiveWormholeMessages' on the address 'targetAddress' on chain 'targetChain' + // with the payload 'abi.encode(amount, payload)' + // (and we encode the amount so it can be checked on the target chain) + function sendUSDCWithPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + uint256 amount + ) internal returns (uint64 sequence) { + MessageKey[] memory messageKeys = new MessageKey[](1); + messageKeys[0] = transferUSDC(amount, targetChain, targetAddress); - const rcv = wh.getChain('Algorand'); + bytes memory userPayload = abi.encode(amount, payload); + address defaultDeliveryProvider = wormholeRelayer + .getDefaultDeliveryProvider(); - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); + (uint256 cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + receiverValue, + gasLimit + ); - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); + sequence = wormholeRelayer.sendToEvm{value: cost}( + targetChain, + targetAddress, + userPayload, + receiverValue, + 0, + gasLimit, + targetChain, + address(0x0), + defaultDeliveryProvider, + messageKeys, + CONSISTENCY_LEVEL_FINALIZED + ); + } - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); + function addressToBytes32CCTP(address addr) private pure returns (bytes32) { + return bytes32(uint256(uint160(addr))); + } +} + ``` - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); +The `CCTPSender` abstract contract exposes the `sendUSDCWithPayloadToEvm` function. This function publishes a CCTP transfer of the provided `amount` of USDC and requests that the transfer be delivered along with a `payload` to the specified `targetAddress` on the `targetChain`. - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); +```solidity +function sendUSDCWithPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + uint256 amount +) internal returns (uint64 sequence) +``` - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); +??? interface "Parameters" - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); + `targetChain` ++"uint16"++ - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); + The target chain for the transfer. - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); + --- - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); + `targetAddress` ++"address"++ - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); + The target address for the transfer. - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); - ``` + --- -Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. + `payload` ++"bytes"++ -```ts -const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, -}); -``` + Arbitrary payload to be delivered to the target chain via Wormhole. -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -(async function () { - const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, - }); - console.log(wh.config.chains.Solana); -})(); - ``` + --- -## Concepts + `gasLimit` ++"uint256"++ -Understanding several higher-level Wormhole concepts and how the SDK abstracts them away will help you use the tools most effectively. The following sections will introduce and discuss the concepts of platforms, chain contexts, addresses, signers, and protocols, how they are used in the Wormhole context, and how the SDK helps ease development in each conceptual area. + The gas limit with which to call `targetAddress`. -### Platforms + --- -While every chain has unique attributes, chains from the same platform typically have standard functionalities they share. The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: + `amount` ++"uint256"++ -- Protocols, such as [Wormhole core](#wormhole-core), preconfigured to suit the selected platform -- Definitions and configurations for types, signers, addresses, and chains -- Helpers configured for dealing with unsigned transactions on the selected platform + The amount of USDC to transfer. -These modules also import and expose essential functions and define types or constants from the chain's native ecosystem to reduce the dependencies needed to interact with a chain using Wormhole. Rather than installing the entire native package for each desired platform, you can install a targeted package of standardized functions and definitions essential to connecting with Wormhole, keeping project dependencies as slim as possible. + --- +??? interface "Returns" -Wormhole currently supports the following platforms: + `sequence` ++"uint64"++ -- EVM -- Solana -- Cosmos -- Sui -- Aptos -- Algorand + Sequence number of the published VAA containing the delivery instructions. -See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. +When the `sendUSDCWithPayloadToEvm` function is called, the following series of actions are executed: -### Chain Context +1. **USDC transfer initiation**: -The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. + - The Circle Token Messenger contract is approved to spend the specified amount of USDC. + - The `depositForBurnWithCaller` function of the Token Messenger contract is invoked + - A key is returned, which is to be provided to the Wormhole relayer for message delivery -```ts -const srcChain = wh.getChain(senderAddress.chain); -const dstChain = wh.getChain(receiverAddress.chain); +2. **Message encoding** - the message `payload` is encoded for transmission via the Wormhole relayer. The encoded value also includes the `amount` so that it can be checked on the target chain +3. **Retrieving delivery provider** - the current default delivery provider's address is retrieved +4. **Cost calculation** - the transfer cost is calculated using the Wormhole relayer's `quoteEVMDeliveryPrice` function +5. **Message dispatch**: -const tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'> -srcChain.getRpcClient(); // => RpcClient<'Evm'> -``` + - The `sendToEvm` function of the Wormhole relayer is called with the encoded payload, the delivery provider's address, and the arguments passed to `sendUSDCWithPayloadToEvm` + - The function must be called with `msg.value` set to the previously calculated cost (from step 4) + - This function publishes an instruction for the delivery provider to relay the payload and VAAs specified by the key (from step 1) to the target address on the target chain -### Addresses +A simple example implementation is as follows: -The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. +```solidity +function sendCrossChainDeposit( + uint16 targetChain, + address targetAddress, + address recipient, + uint256 amount, + uint256, + gasLimit +) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must be quoteCrossChainDeposit(targetChain)" + ); -```ts -// It's possible to convert a string address to its Native address -const ethAddr: NativeAddress<'Evm'> = toNative('Ethereum', '0xbeef...'); + IERC20(USDC).transferFrom(msg.sender, address(this), amount); -// A common type in the SDK is the `ChainAddress` which provides -// the additional context of the `Chain` this address is relevant for -const senderAddress: ChainAddress = Wormhole.chainAddress( - 'Ethereum', - '0xbeef...' -); -const receiverAddress: ChainAddress = Wormhole.chainAddress( - 'Solana', - 'Sol1111...' -); + bytes memory payload = abi.encode(recipient); + sendUSDCWithPayloadToEvm( + targetChain, + targetAddress, // address (on targetChain) to send token and payload to + payload, + 0, // receiver value + gasLimit, + amount + ); +} +``` -// Convert the ChainAddress back to its canonical string address format -const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' +The above example sends a specified amount of USDC and the recipient's address as a payload to a target contract on another chain, ensuring that the correct cost is provided for the cross-chain transfer. -// Or if the ethAddr above is for an emitter and you need the UniversalAddress -const emitterAddr = ethAddr.toUniversalAddress().toString(); -``` +### Receiving Tokens and Messages -### Tokens +To complete the cross-chain transfer, you must invoke the `redeemTokensWithPayload` function on the target Wormhole Circle Integration contract. This function verifies the message's authenticity, decodes the payload, confirms the recipient and sender, checks message delivery, and then calls the `receiveMessage` function of the [Message Transmitter](#message-transmitter-contract) contract. -Similar to the `ChainAddress` type, the `TokenId` type provides the chain and address of a given token. The following snippet introduces `TokenId`, a way to uniquely identify any token, whether it's a standard token or a blockchain's native currency (like ETH for Ethereum). +Using the Wormhole-deployed relayer automatically triggers the `receiveWormholeMessages` function. This function is defined in the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} from the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank} and is implemented within the [`CCTPReceiver` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. -Wormhole uses their contract address to create a `TokenId` for standard tokens. For native currencies, Wormhole uses the keyword `native` instead of an address. This makes it easy to work with any type of token consistently. +??? code "CCTP Receiver contract" -Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. + ```solidity + abstract contract CCTPReceiver is CCTPBase { + function redeemUSDC( + bytes memory cctpMessage + ) internal returns (uint256 amount) { + (bytes memory message, bytes memory signature) = abi.decode( + cctpMessage, + (bytes, bytes) + ); + uint256 beforeBalance = IERC20(USDC).balanceOf(address(this)); + circleMessageTransmitter.receiveMessage(message, signature); + return IERC20(USDC).balanceOf(address(this)) - beforeBalance; + } -```ts -const sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...'); + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable { + // Currently, 'sendUSDCWithPayloadToEVM' only sends one CCTP transfer + // That can be modified if the integrator desires to send multiple CCTP transfers + // in which case the following code would have to be modified to support + // redeeming these multiple transfers and checking that their 'amount's are accurate + require( + additionalMessages.length <= 1, + "CCTP: At most one Message is supported" + ); -const gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native'); + uint256 amountUSDCReceived; + if (additionalMessages.length == 1) + amountUSDCReceived = redeemUSDC(additionalMessages[0]); -const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' -``` + (uint256 amount, bytes memory userPayload) = abi.decode( + payload, + (uint256, bytes) + ); -### Signers + // Check that the correct amount was received + // It is important to verify that the 'USDC' sent in by the relayer is the same amount + // that the sender sent in on the source chain + require(amount == amountUSDCReceived, "Wrong amount received"); -Certain methods of signing transactions require a `Signer` interface in the SDK. Depending on the specific requirements, this interface can be fulfilled by either a `SignOnlySigner` or a `SignAndSendSigner`. A signer can be created by wrapping an offline or web wallet. + receivePayloadAndUSDC( + userPayload, + amountUSDCReceived, + sourceAddress, + sourceChain, + deliveryHash + ); + } -A `SignOnlySigner` is used when the signer isn't connected to the network or prefers not to broadcast transactions themselves. It accepts an array of unsigned transactions and returns an array of signed and serialized transactions. Before signing, the transactions may be inspected or altered. It's important to note that the serialization process is chain-specific. Refer to the testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank} or [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for an example of how to implement a signer for a specific chain or platform. + // Implement this function to handle in-bound deliveries that include a CCTP transfer + function receivePayloadAndUSDC( + bytes memory payload, + uint256 amountUSDCReceived, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) internal virtual {} +} + ``` -Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. +Although you do not need to interact with the `receiveWormholeMessages` function directly, it's important to understand what it does. This function processes cross-chain messages and USDC transfers via Wormhole's Circle (CCTP) Bridge. Here's a summary of what it does: -```ts -export type Signer = SignOnlySigner | SignAndSendSigner; +1. **Validate additional messages** - the function checks that there is at most one CCTP transfer message in the `additionalMessages` array, as it currently only supports processing a single CCTP transfer +2. **Redeem USDC**: + - If there is a CCTP message, it calls the `redeemUSDC` function of the `CCTPReceiver` contract to decode and redeem the USDC + - This results in the call of the `receiveMessage` function of Circle's Message Transmitter contract to redeem the USDC based on the provided message and signature + - The amount of USDC received is calculated by subtracting the contract's previous balance from the current balance after redeeming the USDC +3. **Decode payload** - the incoming payload is decoded, extracting both the expected amount of USDC and a `userPayload` (which could be any additional data) +4. **Verify the amount** - it ensures that the amount of USDC received matches the amount encoded in the payload. If the amounts don't match, the transaction is reverted +5. **Handle the payload and USDC** - after verifying the amounts, `receivePayloadAndUSDC` is called, which is meant to handle the actual logic for processing the received payload and USDC transfer -export interface SignOnlySigner { - chain(): ChainName; - address(): string; - // Accept an array of unsigned transactions and return - // an array of signed and serialized transactions. - // The transactions may be inspected or altered before - // signing. - sign(tx: UnsignedTransaction[]): Promise; -} +You'll need to implement the `receivePayloadAndUSDC` function to transfer the USDC and handle the payload as your application needs. A simple example implementation is as follows: -export interface SignAndSendSigner { - chain(): ChainName; - address(): string; - // Accept an array of unsigned transactions and return - // an array of transaction ids in the same order as the - // unsignedTransactions array. - signAndSend(tx: UnsignedTransaction[]): Promise; -} +```solidity +function receivePayloadAndUSDC( + bytes memory payload, + uint256 amountUSDCReceived, + bytes32, // sourceAddress + uint16, // sourceChain + bytes32 // deliveryHash +) internal override onlyWormholeRelayer { + address recipient = abi.decode(payload, (address)); + + IERC20(USDC).transfer(recipient, amountUSDCReceived); +} ``` -#### Set Up a Signer with Ethers.js +## Complete Example -To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: +To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. +--- END CONTENT --- -```javascript -import { ethers } from 'ethers'; +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ +--- BEGIN CONTENT --- +--- +title: Wormhole Connect +description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. +categories: Connect, Transfer +--- -// Update the following variables -const rpcUrl = 'INSERT_RPC_URL'; -const privateKey = 'INSERT_PRIVATE_KEY'; -const toAddress = 'INSERT_RECIPIENT_ADDRESS'; +# Wormhole Connect -// Set up a provider and signer -const provider = new ethers.JsonRpcProvider(rpcUrl); -const signer = new ethers.Wallet(privateKey, provider); +Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. -// Example: Signing and sending a transaction -async function sendTransaction() { - const tx = { - to: toAddress, - value: ethers.parseUnits('0.1'), // Sending 0.1 ETH - gasPrice: await provider.getGasPrice(), - gasLimit: ethers.toBeHex(21000), - }; +## Build with Connect - const transaction = await signer.sendTransaction(tx); - console.log('Transaction hash:', transaction.hash); -} -sendTransaction(); -``` +[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] - - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions +## See It In Action - - **`signer`** - represents the account that will sign the transaction. In this case, you’re creating a signer using the private key associated with the account. The signer is responsible for authorizing transactions by digitally signing them with the private key +Wormhole Connect is deployed live in several production apps. Here are a few: - - **`Wallet`** - combines both the provider (for blockchain interaction) and the signer (for transaction authorization), allowing you to sign and send transactions programmatically +- [Portal Bridge](https://portalbridge.com/){target=\_blank} +- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} +- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} -These components work together to create, sign, and submit a transaction to the blockchain. +Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). -???- tip "Managing Private Keys Securely" - Handling private keys is unavoidable, so it’s crucial to manage them securely. Here are some best practices: +## Next Steps - - **Use environment variables** - avoid hardcoding private keys in your code. Use environment variables or secret management tools to inject private keys securely - - **Hardware wallets** - for production environments, consider integrating hardware wallets to keep private keys secure while allowing programmatic access through the SDK +
-### Protocols +- :octicons-tools-16:{ .lg .middle} **Get Started Now** -While Wormhole is a Generic Message Passing (GMP) protocol, several protocols have been built to provide specific functionality. If available, each protocol will have a platform-specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain. + --- -#### Wormhole Core + Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. -The core protocol underlies all Wormhole activity. This protocol is responsible for emitting the message containing the information necessary to perform bridging, including the [emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter){target=\_blank}, the [sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence){target=\_blank} for the message, and the payload of the message itself. + [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) -The following example demonstrates sending and verifying a message using the Wormhole Core protocol on Solana. +- :octicons-tools-16:{ .lg .middle } **Multichain Swap** -First, initialize a Wormhole instance for the Testnet environment, specifically for the Solana chain. Then, obtain a signer and its associated address, which will be used to sign transactions. + --- -Next, get a reference to the core messaging bridge, which is the main interface for interacting with Wormhole's cross-chain messaging capabilities. -The code then prepares a message for publication. This message includes: + This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. -- The sender's address -- The message payload (in this case, the encoded string `lol`) -- A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) -After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. + [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) -The code then waits for the Wormhole network to process and sign the message, turning it into a Verified Action Approval (VAA). This VAA is retrieved in a `Uint8Array` format, with a timeout of 60 seconds. -Lastly, the code will demonstrate how to verify the message on the receiving end. A verification transaction is prepared using the original sender's address and the VAA, and finally, this transaction is signed and sent. +- :octicons-tools-16:{ .lg .middle } **Connect FAQs** -???+ code "View the complete script" - ```ts - import { encoding, signSendWait, wormhole } from '@wormhole-foundation/sdk'; -import { getSigner } from './helpers/index.js'; -import solana from '@wormhole-foundation/sdk/solana'; -import evm from '@wormhole-foundation/sdk/evm'; + --- -(async function () { - const wh = await wormhole('Testnet', [solana, evm]); + Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - const chain = wh.getChain('Avalanche'); - const { signer, address } = await getSigner(chain); + [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - // Get a reference to the core messaging bridge - const coreBridge = await chain.getWormholeCore(); +- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** - // Generate transactions, sign and send them - const publishTxs = coreBridge.publishMessage( - // Address of sender (emitter in VAA) - address.address, - // Message to send (payload in VAA) - encoding.bytes.encode('lol'), - // Nonce (user defined, no requirement for a specific value, useful to provide a unique identifier for the message) - 0, - // ConsistencyLevel (ie finality of the message, see wormhole docs for more) - 0 - ); - // Send the transaction(s) to publish the message - const txids = await signSendWait(chain, publishTxs, signer); + --- - // Take the last txid in case multiple were sent - // The last one should be the one containing the relevant - // event or log info - const txid = txids[txids.length - 1]; + Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - // Grab the wormhole message id from the transaction logs or storage - const [whm] = await chain.parseTransaction(txid!.txid); + [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) - // Wait for the vaa to be signed and available with a timeout - const vaa = await wh.getVaa(whm!, 'Uint8Array', 60_000); - console.log(vaa); +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ +--- BEGIN CONTENT --- +--- +title: Overview +description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. +categories: Connect, Transfer +--- + +# Wormhole Connect + +## Introduction {: #introduction } - // Note: calling verifyMessage manually is typically not a useful thing to do - // As the VAA is typically submitted to the counterpart contract for - // A given protocol and the counterpart contract will verify the VAA - // This is simply for demo purposes - const verifyTxs = coreBridge.verifyMessage(address.address, vaa!); - console.log(await signSendWait(chain, verifyTxs, signer)); -})(); - ``` +Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. -The payload contains the information necessary to perform whatever action is required based on the protocol that uses it. +The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. -#### Token Bridge +## Features {: #features } -The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. +Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: -```ts -import { signSendWait } from '@wormhole-foundation/sdk'; +- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) +- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) +- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer +- Ability to configure any token to bridge via Wormhole +- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination -const tb = await srcChain.getTokenBridge(); +For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. -const token = '0xdeadbeef...'; -const txGenerator = tb.createAttestation(token); -const txids = await signSendWait(srcChain, txGenerator, src.signer); -``` +## Integrate Connect {: #integrate-connect } -Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. +### Import Directly into a React App {: #import-directly-into-a-react-app} -## Transfers +First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} -While using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens. +```bash +npm i @wormhole-foundation/wormhole-connect +``` -The `WormholeTransfer` interface provides a convenient abstraction to encapsulate the steps involved in a cross-chain transfer. +Now you can import the React component: -### Token Transfers +```ts +import WormholeConnect from '@wormhole-foundation/wormhole-connect'; -Performing a token transfer is trivial for any source and destination chains. You can create a new `Wormhole` object to make objects like `TokenTransfer` and `CircleTransfer`, to transfer tokens between chains. +function App() { + return ; +} +``` -The following example demonstrates the process of initiating and completing a token transfer. It starts by creating a `TokenTransfer` object, which tracks the transfer's state throughout its lifecycle. The code then obtains a quote for the transfer, ensuring the amount is sufficient to cover fees and any requested native gas. +### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} -The transfer process is divided into three main steps: +If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. -1. Initiating the transfer on the source chain -2. Waiting for the transfer to be attested (if not automatic) -3. Completing the transfer on the destination chain +```ts title="v1.x" +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); -```ts -const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.delivery?.automatic ?? false, - route.payload, - route.delivery?.nativeGas - ); +wormholeConnectHosted(container); +``` - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); - console.log(quote); +For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +???- code "v0.x" + Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. - // 1) Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Started transfer: `, srcTxids); + ```html + +
+ + + + ``` - // If automatic, we're done - if (route.delivery?.automatic) return xfer; + For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: - // 2) Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - const attestIds = await xfer.fetchAttestation(60_000); - console.log(`Got Attestation: `, attestIds); + ```html + +
+ + + + ``` - // 3) Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -``` +It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. -??? code "View the complete script" - ```ts hl_lines="122" - import { - Chain, - Network, - TokenId, - TokenTransfer, - Wormhole, - amount, - isTokenId, - wormhole, -} from '@wormhole-foundation/sdk'; +## Configuration {: #configuration} -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { SignerStuff, getSigner, waitLog } from './helpers/index.js'; +This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. -(async function () { - // Init Wormhole object, passing config for which network - // to use (e.g. Mainnet/Testnet) and what Platforms to support - const wh = await wormhole('Testnet', [evm, solana]); +The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: - // Grab chain Contexts -- these hold a reference to a cached rpc client - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Solana'); + - Use custom styles + - Restrict the chains that you allow in your app + - Add support for your project's token, and eliminate tokens you don't want to reduce noise + - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) + - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); +For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. +--- END CONTENT --- - // A TokenId is just a `{chain, address}` pair and an alias for ChainAddress - // The `address` field must be a parsed address. - // You can get a TokenId (or ChainAddress) prepared for you - // by calling the static `chainAddress` method on the Wormhole class. - // e.g. - // wAvax on Solana - // const token = Wormhole.tokenId("Solana", "3Ftc5hTz9sG4huk79onufGiebJNDMZNL8HYgdMJ9E7JR"); - // wSol on Avax - // const token = Wormhole.tokenId("Avalanche", "0xb10563644a6AB8948ee6d7f5b0a1fb15AaEa1E03"); +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Installation +description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. +categories: NTT, Transfer +--- - // Normalized given token decimals later but can just pass bigints as base units - // Note: The Token bridge will dedust past 8 decimals - // This means any amount specified past that point will be returned - // To the caller - const amt = '0.05'; +# Install the Native Token Transfers CLI - // With automatic set to true, perform an automatic transfer. This will invoke a relayer - // Contract intermediary that knows to pick up the transfers - // With automatic set to false, perform a manual transfer from source to destination - // Of the token - // On the destination side, a wrapped version of the token will be minted - // To the address specified in the transfer VAA - const automatic = false; +In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. - // The Wormhole relayer has the ability to deliver some native gas funds to the destination account - // The amount specified for native gas will be swapped for the native gas token according - // To the swap rate provided by the contract, denominated in native gas tokens - const nativeGas = automatic ? '0.01' : undefined; +To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - // Get signer from local key but anything that implements - // Signer interface (e.g. wrapper around web wallet) should work - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +
- // Used to normalize the amount to account for the tokens decimals - const decimals = isTokenId(token) - ? Number(await wh.getDecimals(token.chain, token.address)) - : sendChain.config.nativeTokenDecimals; +## Install NTT CLI - // Set this to true if you want to perform a round trip transfer - const roundTrip: boolean = false; +The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: - // Set this to the transfer txid of the initiating transaction to recover a token transfer - // And attempt to fetch details about its progress. - let recoverTxid = undefined; +- Install [Bun](https://bun.sh/docs/installation){target=\_blank} - // Finally create and perform the transfer given the parameters set above - const xfer = !recoverTxid - ? // Perform the token transfer - await tokenTransfer( - wh, - { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - delivery: { - automatic, - nativeGas: nativeGas - ? amount.units(amount.parse(nativeGas, decimals)) - : undefined, - }, - }, - roundTrip - ) - : // Recover the transfer from the originating txid - await TokenTransfer.from(wh, { - chain: source.chain.chain, - txid: recoverTxid, - }); +Follow these steps to install the NTT CLI: - const receipt = await waitLog(wh, xfer); +1. Run the installation command in your terminal: - // Log out the results - console.log(receipt); -})(); + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - delivery?: { - automatic: boolean; - nativeGas?: bigint; - }; - payload?: Uint8Array; - }, - roundTrip?: boolean -): Promise> { - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.delivery?.automatic ?? false, - route.payload, - route.delivery?.nativeGas - ); +2. Verify the NTT CLI is installed: + + ```bash + ntt --version + ``` - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); - console.log(quote); +3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +## Update NTT CLI - // 1) Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Started transfer: `, srcTxids); +To update an existing NTT CLI installation, run the following command in your terminal: - // If automatic, we're done - if (route.delivery?.automatic) return xfer; +```bash +ntt update +``` - // 2) Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - const attestIds = await xfer.fetchAttestation(60_000); - console.log(`Got Attestation: `, attestIds); +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. - // 3) Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); +For local development, you can update your CLI version from a specific branch or install from a local path. - // If no need to send back, dip - if (!roundTrip) return xfer; +To install from a specific branch, run: - const { destinationToken: token } = quote; - return await tokenTransfer(wh, { - ...route, - token: token.token, - amount: token.amount, - source: route.destination, - destination: route.source, - }); -} - - ``` +```bash +ntt update --branch foo +``` -Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` -### Native USDC Transfers +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. -You can also transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. Please note that if the transfer is set to `Automatic` mode, a fee for performing the relay will be included in the quote. This fee is deducted from the total amount requested to be sent. For example, if the user wishes to receive `1.0` on the destination, the amount sent should be adjusted to `1.0` plus the relay fee. The same principle applies to native gas drop offs. +## Where to Go Next -In the following example, the `wh.circleTransfer` function is called with several parameters to set up the transfer. It takes the amount to be transferred (in the token's base units), the sender's chain and address, and the receiver's chain and address. The function also allows specifying whether the transfer should be automatic, meaning it will be completed without further user intervention. +
-An optional payload can be included with the transfer, though it's set to undefined in this case. Finally, if the transfer is automatic, you can request that native gas (the blockchain's native currency used for transaction fees) be sent to the receiver along with the transferred tokens. -When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. +- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** -```ts -// Amount as bigint (base units) - req.amount, - // Sender chain/address - src.address, - // Receiver chain/address - dst.address, - // Automatic delivery boolean - req.automatic, - // Payload to be sent with the transfer - undefined, - // If automatic, native gas can be requested to be sent to the receiver - req.nativeGas - ); + --- - // Note, if the transfer is requested to be Automatic, a fee for performing the relay - // will be present in the quote. The fee comes out of the amount requested to be sent. - // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. - // The same applies for native gas dropoff - const quote = await CircleTransfer.quoteTransfer( - src.chain, - dst.chain, - xfer.transfer - ); - console.log('Quote', quote); + Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(src.signer); - console.log(`Started Transfer: `, srcTxids); + [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - if (req.automatic) { - const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); - console.log(`Finished relay: `, relayStatus); - return; - } +- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(60_000); - console.log(`Got Attestation: `, attestIds); + --- - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(dst.signer); - console.log(`Completed Transfer: `, dstTxids); -} -``` + Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -??? code "View the complete script" - ```ts - import { - Chain, - CircleTransfer, - Network, - Signer, - TransactionId, - TransferState, - Wormhole, - amount, - wormhole, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js'; + [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) -/* -Notes: -Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains +
+--- END CONTENT --- -AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC -*/ -// +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer +--- -(async function () { - // Init the Wormhole object, passing in the config for which network - // to use (e.g. Mainnet/Testnet) and what Platforms to support - const wh = await wormhole('Testnet', [evm, solana]); +# Native Token Transfers Post Deployment - // Grab chain Contexts - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Solana'); +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - // Get signer from local key but anything that implements - // Signer interface (e.g. wrapper around web wallet) should work - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment - // 6 decimals for USDC (except for BSC, so check decimals before using this) - const amt = amount.units(amount.parse('0.2', 6)); +## Manual Relaying for Solana Transfers - // Choose whether or not to have the attestation delivered for you - const automatic = false; +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. - // If the transfer is requested to be automatic, you can also request that - // during redemption, the receiver gets some amount of native gas transferred to them - // so that they may pay for subsequent transactions - // The amount specified here is denominated in the token being transferred (USDC here) - const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. - await cctpTransfer(wh, source, destination, { - amount: amt, - automatic, - nativeGas, - }); +[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. -})(); +## Where to Go Next -async function cctpTransfer( - wh: Wormhole, - src: SignerStuff, - dst: SignerStuff, - req: { - amount: bigint; - automatic: boolean; - nativeGas?: bigint; - } -) { +
- const xfer = await wh.circleTransfer( - // Amount as bigint (base units) - req.amount, - // Sender chain/address - src.address, - // Receiver chain/address - dst.address, - // Automatic delivery boolean - req.automatic, - // Payload to be sent with the transfer - undefined, - // If automatic, native gas can be requested to be sent to the receiver - req.nativeGas - ); +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** - // Note, if the transfer is requested to be Automatic, a fee for performing the relay - // will be present in the quote. The fee comes out of the amount requested to be sent. - // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. - // The same applies for native gas dropoff - const quote = await CircleTransfer.quoteTransfer( - src.chain, - dst.chain, - xfer.transfer - ); - console.log('Quote', quote); + --- - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(src.signer); - console.log(`Started Transfer: `, srcTxids); + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. - if (req.automatic) { - const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); - console.log(`Finished relay: `, relayStatus); - return; - } + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(60_000); - console.log(`Got Attestation: `, attestIds); +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(dst.signer); - console.log(`Completed Transfer: `, dstTxids); -} + --- -export async function completeTransfer( - wh: Wormhole, - txid: TransactionId, - signer: Signer -): Promise { + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. + + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) + +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers (NTT) +description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. +categories: NTT, Transfer +--- + +# Native Token Transfers - const xfer = await CircleTransfer.from(wh, txid); +Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. - const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); - console.log('Got attestation: ', attestIds); +Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. - const dstTxIds = await xfer.completeTransfer(signer); - console.log('Completed transfer: ', dstTxIds); -} -
- ``` +## Quickstart -### Recovering Transfers +If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. -It may be necessary to recover an abandoned transfer before it is completed. To do this, instantiate the `Transfer` class with the `from` static method and pass one of several types of identifiers. A `TransactionId` or `WormholeMessageId` may be used to recover the transfer. +The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: -```ts -const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); - console.log('Got attestation: ', attestIds); +[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] - const dstTxIds = await xfer.completeTransfer(signer); - console.log('Completed transfer: ', dstTxIds); -``` +## Deploy NTTs with Launchpad -??? code "View the complete script" - ```ts hl_lines="130" - import { - Chain, - CircleTransfer, - Network, - Signer, - TransactionId, - TransferState, - Wormhole, - amount, - wormhole, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js'; +If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. -/* -Notes: -Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains +Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. -AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC -*/ -// +## Additional Resources -(async function () { - // Init the Wormhole object, passing in the config for which network - // to use (e.g. Mainnet/Testnet) and what Platforms to support - const wh = await wormhole('Testnet', [evm, solana]); +
- // Grab chain Contexts - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Solana'); +- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** - // Get signer from local key but anything that implements - // Signer interface (e.g. wrapper around web wallet) should work - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); + --- - // 6 decimals for USDC (except for BSC, so check decimals before using this) - const amt = amount.units(amount.parse('0.2', 6)); + The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - // Choose whether or not to have the attestation delivered for you - const automatic = false; + [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - // If the transfer is requested to be automatic, you can also request that - // during redemption, the receiver gets some amount of native gas transferred to them - // so that they may pay for subsequent transactions - // The amount specified here is denominated in the token being transferred (USDC here) - const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; +- :octicons-question-16:{ .lg .middle } **NTT FAQs** - await cctpTransfer(wh, source, destination, { - amount: amt, - automatic, - nativeGas, - }); + --- -})(); + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -async function cctpTransfer( - wh: Wormhole, - src: SignerStuff, - dst: SignerStuff, - req: { - amount: bigint; - automatic: boolean; - nativeGas?: bigint; - } -) { + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) - const xfer = await wh.circleTransfer( - // Amount as bigint (base units) - req.amount, - // Sender chain/address - src.address, - // Receiver chain/address - dst.address, - // Automatic delivery boolean - req.automatic, - // Payload to be sent with the transfer - undefined, - // If automatic, native gas can be requested to be sent to the receiver - req.nativeGas - ); +
+--- END CONTENT --- - // Note, if the transfer is requested to be Automatic, a fee for performing the relay - // will be present in the quote. The fee comes out of the amount requested to be sent. - // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. - // The same applies for native gas dropoff - const quote = await CircleTransfer.quoteTransfer( - src.chain, - dst.chain, - xfer.transfer - ); - console.log('Quote', quote); +Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ +--- BEGIN CONTENT --- +--- +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +categories: NTT, Transfer +--- - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(src.signer); - console.log(`Started Transfer: `, srcTxids); +# Managers and Transceivers - if (req.automatic) { - const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); - console.log(`Finished relay: `, relayStatus); - return; - } +## Managers - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(60_000); - console.log(`Got Attestation: `, attestIds); +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(dst.signer); - console.log(`Completed Transfer: `, dstTxids); -} +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain -export async function completeTransfer( - wh: Wormhole, - txid: TransactionId, - signer: Signer -): Promise { + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) + ``` - const xfer = await CircleTransfer.from(wh, txid); +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer - const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); - console.log('Got attestation: ', attestIds); + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` - const dstTxIds = await xfer.completeTransfer(signer); - console.log('Completed transfer: ', dstTxIds); -} - +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected + + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner ``` -## Routes +## Transceivers -While a specific `WormholeTransfer`, such as `TokenTransfer` or `CCTPTransfer`, may be used, the developer must know exactly which transfer type to use for a given request. +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: -To provide a more flexible and generic interface, the `Wormhole` class provides a method to produce a `RouteResolver` that can be configured with a set of possible routes to be supported. +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -The following section demonstrates setting up and validating a token transfer using Wormhole's routing system. + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -```ts -const resolver = wh.resolver([ - routes.TokenBridgeRoute, // manual token bridge - routes.AutomaticTokenBridgeRoute, // automatic token bridge - routes.CCTPRoute, // manual CCTP - routes.AutomaticCCTPRoute, // automatic CCTP - routes.AutomaticPorticoRoute, // Native eth transfers - ]); -``` +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -Once created, the resolver can be used to provide a list of input and possible output tokens. + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -```ts -const srcTokens = await resolver.supportedSourceTokens(sendChain); - console.log( - 'Allowed source tokens: ', - srcTokens.map((t) => canonicalAddress(t)) - ); +## Lifecycle of a Message - const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); +### EVM - // Given the send token, what can we possibly get on the destination chain? - const destTokens = await resolver.supportedDestinationTokens( - sendToken, - sendChain, - destChain - ); - console.log( - 'For the given source token and routes configured, the following tokens may be receivable: ', - destTokens.map((t) => canonicalAddress(t)) - ); - // Grab the first one for the example - const destinationToken = destTokens[0]!; -``` +#### Transfer -Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfill the request. Creating a transfer request fetches the token details since all routes will need to know about the tokens. +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. -```ts -// Since all routes will need to know about the tokens - const tr = await routes.RouteTransferRequest.create(wh, { - source: sendToken, - destination: destinationToken, - }); +**Events** - // Resolve the transfer request to a set of routes that can perform it - const foundRoutes = await resolver.findRoutes(tr); - console.log( - 'For the transfer parameters, we found these routes: ', - foundRoutes - ); +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); ``` -Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - -After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. +#### Rate Limit -After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. -```ts -'This route offers the following default options', - bestRoute.getDefaultOptions() - ); +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. - // Specify the amount as a decimal string - const amt = '0.001'; - // Create the transfer params for this request - const transferParams = { amount: amt, options: { nativeGas: 0 } }; +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. - // Validate the transfer params passed, this returns a new type of ValidatedTransferParams - // which (believe it or not) is a validated version of the input params - // This new var must be passed to the next step, quote - const validated = await bestRoute.validate(tr, transferParams); - if (!validated.valid) throw validated.error; - console.log('Validated parameters: ', validated.params); +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. - // Get a quote for the transfer, this too returns a new type that must - // be passed to the next step, execute (if you like the quote) - const quote = await bestRoute.quote(tr, validated.params); - if (!quote.success) throw quote.error; - console.log('Best route quote: ', quote); -``` +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. -Finally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`. +**Events** ```ts -tr, - sender.signer, - quote, - receiver.address - ); - console.log('Initiated transfer with receipt: ', receipt); +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); ``` -??? code "View the complete script" - - ```ts - import { - Wormhole, - canonicalAddress, - routes, - wormhole, -} from '@wormhole-foundation/sdk'; - -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/index.js'; +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` -(async function () { - // Setup - const wh = await wormhole('Testnet', [evm, solana]); +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` - // Get chain contexts - const sendChain = wh.getChain('Avalanche'); - const destChain = wh.getChain('Solana'); +#### Send - // Get signers from local config - const sender = await getSigner(sendChain); - const receiver = await getSigner(destChain); +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). - // Create new resolver, passing the set of routes to consider - const resolver = wh.resolver([ - routes.TokenBridgeRoute, // manual token bridge - routes.AutomaticTokenBridgeRoute, // automatic token bridge - routes.CCTPRoute, // manual CCTP - routes.AutomaticCCTPRoute, // automatic CCTP - routes.AutomaticPorticoRoute, // Native eth transfers - ]); +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. - // What tokens are available on the source chain? - const srcTokens = await resolver.supportedSourceTokens(sendChain); - console.log( - 'Allowed source tokens: ', - srcTokens.map((t) => canonicalAddress(t)) - ); +**Events** - const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` - // Given the send token, what can we possibly get on the destination chain? - const destTokens = await resolver.supportedDestinationTokens( - sendToken, - sendChain, - destChain - ); - console.log( - 'For the given source token and routes configured, the following tokens may be receivable: ', - destTokens.map((t) => canonicalAddress(t)) - ); - // Grab the first one for the example - const destinationToken = destTokens[0]!; +#### Receive - // Creating a transfer request fetches token details - // Since all routes will need to know about the tokens - const tr = await routes.RouteTransferRequest.create(wh, { - source: sendToken, - destination: destinationToken, - }); +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. - // Resolve the transfer request to a set of routes that can perform it - const foundRoutes = await resolver.findRoutes(tr); - console.log( - 'For the transfer parameters, we found these routes: ', - foundRoutes - ); +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. - const bestRoute = foundRoutes[0]!; - console.log('Selected: ', bestRoute); +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. - console.log( - 'This route offers the following default options', - bestRoute.getDefaultOptions() - ); +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. - // Specify the amount as a decimal string - const amt = '0.001'; - // Create the transfer params for this request - const transferParams = { amount: amt, options: { nativeGas: 0 } }; +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. - // Validate the transfer params passed, this returns a new type of ValidatedTransferParams - // which (believe it or not) is a validated version of the input params - // This new var must be passed to the next step, quote - const validated = await bestRoute.validate(tr, transferParams); - if (!validated.valid) throw validated.error; - console.log('Validated parameters: ', validated.params); +**Events** - // Get a quote for the transfer, this too returns a new type that must - // be passed to the next step, execute (if you like the quote) - const quote = await bestRoute.quote(tr, validated.params); - if (!quote.success) throw quote.error; - console.log('Best route quote: ', quote); +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` - // If you're sure you want to do this, set this to true - const imSure = false; - if (imSure) { - // Now the transfer may be initiated - // A receipt will be returned, guess what you gotta do with that? - const receipt = await bestRoute.initiate( - tr, - sender.signer, - quote, - receiver.address - ); - console.log('Initiated transfer with receipt: ', receipt); +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` - // Kick off a wait log, if there is an opportunity to complete, this function will do it - // See the implementation for how this works - await routes.checkAndCompleteTransfer(bestRoute, receipt, receiver.signer); - } else { - console.log('Not initiating transfer (set `imSure` to true to do so)'); - } -})(); - ``` +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -See the `router.ts` example in the [examples directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/examples){target=\_blank} for a full working example. +#### Mint or Unlock -### Routes as Plugins +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -Routes can be imported from any npm package that exports them and configured with the resolver. Custom routes must extend [`Route`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L21-L64){target=\_blank} and implement [`StaticRouteMethods`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L101){target=\_blank}. +**Events** ```ts -import { Network, routes } from '@wormhole-foundation/sdk-connect'; - -export class CustomRoute - extends routes.Route - implements routes.StaticRouteMethods -{ - static meta = { - name: 'CustomRoute', - }; - // implementation... -} - +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); ``` -A noteworthy example of a route exported from a separate npm package is Wormhole Native Token Transfers (NTT). See the [`NttAutomaticRoute`](https://github.com/wormhole-foundation/native-token-transfers/blob/66f8e414223a77f5c736541db0a7a85396cab71c/sdk/route/src/automatic.ts#L48){target=\_blank} route implementation. - -## See Also +### Solana -The TSdoc is available [on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank}. ---- END CONTENT --- +#### Transfer -Doc-Content: https://wormhole.com/docs/build/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Interacting with CCTP Contracts -description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -categories: Transfer ---- +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. -# Get Started with CCTP +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -## Introduction +Depending on the mode and instruction, the following will be produced in the program logs: -Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` -As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. -This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. +#### Rate Limit -## Prerequisites +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. -To interact with the Wormhole CCTP, you'll need the following: +If the transfer amount fits within the current capacity: -- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. -## Wormhole's CCTP Integration Contract +If the transfer amount doesn't fit within the current capacity: -Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. +#### Send -This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. + +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. !!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. -??? code "Circle Integration contract" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; +The following will be produced in the program logs: -import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IWormhole} from "wormhole/interfaces/IWormhole.sol"; -import {BytesLib} from "wormhole/libraries/external/BytesLib.sol"; +```ts +Program log: Instruction: ReleaseOutbound +``` -import {ICircleBridge} from "../interfaces/circle/ICircleBridge.sol"; +#### Receive -import {CircleIntegrationGovernance} from "./CircleIntegrationGovernance.sol"; -import {CircleIntegrationMessages} from "./CircleIntegrationMessages.sol"; +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. -/** - * @notice This contract burns and mints Circle-supported tokens by using Circle's Cross-Chain Transfer Protocol. It also emits - * Wormhole messages with arbitrary payloads to allow for additional composability when performing cross-chain - * transfers of Circle-suppored assets. - */ -contract CircleIntegration is - CircleIntegrationMessages, - CircleIntegrationGovernance, - ReentrancyGuard -{ - using BytesLib for bytes; +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. - /** - * @notice Emitted when Circle-supported assets have been minted to the mintRecipient - * @param emitterChainId Wormhole chain ID of emitter contract on source chain - * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on source chain - * @param sequence Sequence of Wormhole message used to mint tokens - */ - event Redeemed( - uint16 indexed emitterChainId, - bytes32 indexed emitterAddress, - uint64 indexed sequence - ); +The following will be produced in the program logs: - /** - * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits - * a Wormhole message containing a user-specified payload with instructions for what to do with - * the Circle-supported assets once they have been minted on the target chain. - * @dev reverts if: - * - user passes insufficient value to pay Wormhole message fee - * - `token` is not supported by Circle Bridge - * - `amount` is zero - * - `targetChain` is not supported - * - `mintRecipient` is bytes32(0) - * @param transferParams Struct containing the following attributes: - * - `token` Address of the token to be burned - * - `amount` Amount of `token` to be burned - * - `targetChain` Wormhole chain ID of the target blockchain - * - `mintRecipient` The recipient wallet or contract address on the target chain - * @param batchId ID for Wormhole message batching - * @param payload Arbitrary payload to be delivered to the target chain via Wormhole - * @return messageSequence Wormhole sequence number for this contract - */ - function transferTokensWithPayload( - TransferParameters memory transferParams, - uint32 batchId, - bytes memory payload - ) public payable nonReentrant returns (uint64 messageSequence) { - // cache wormhole instance and fees to save on gas - IWormhole wormhole = wormhole(); - uint256 wormholeFee = wormhole.messageFee(); +```ts +Program log: Instruction: ReceiveMessage +``` - // confirm that the caller has sent enough ether to pay for the wormhole message fee - require(msg.value == wormholeFee, "insufficient value"); +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` - // should be the target contract (or wallet) composing on this contract. - (uint64 nonce, uint256 amountReceived) = _transferTokens( - transferParams.token, - transferParams.amount, - transferParams.targetChain, - transferParams.mintRecipient - ); +The following will be produced in the program logs: - // encode DepositWithPayload message - bytes memory encodedMessage = encodeDepositWithPayload( - DepositWithPayload({ - token: addressToBytes32(transferParams.token), - amount: amountReceived, - sourceDomain: localDomain(), - targetDomain: getDomainFromChainId(transferParams.targetChain), - nonce: nonce, - fromAddress: addressToBytes32(msg.sender), - mintRecipient: transferParams.mintRecipient, - payload: payload - }) - ); +```ts +Program log: Instruction: Redeem +``` - // send the DepositWithPayload wormhole message - messageSequence = wormhole.publishMessage{value: wormholeFee}( - batchId, - encodedMessage, - wormholeFinality() - ); - } +#### Mint or Unlock - function _transferTokens( - address token, - uint256 amount, - uint16 targetChain, - bytes32 mintRecipient - ) internal returns (uint64 nonce, uint256 amountReceived) { - // sanity check user input - require(amount > 0, "amount must be > 0"); - require(mintRecipient != bytes32(0), "invalid mint recipient"); - require(isAcceptedToken(token), "token not accepted"); - require( - getRegisteredEmitter(targetChain) != bytes32(0), - "target contract not registered" - ); +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. - // take custody of tokens - amountReceived = custodyTokens(token, amount); +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. - // cache Circle Bridge instance - ICircleBridge circleBridge = circleBridge(); +Depending on the mode and instruction, the following will be produced in the program logs: - // approve the Circle Bridge to spend tokens - SafeERC20.safeApprove( - IERC20(token), - address(circleBridge), - amountReceived - ); +```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock +``` +--- END CONTENT --- - // burn tokens on the bridge - nonce = circleBridge.depositForBurnWithCaller( - amountReceived, - getDomainFromChainId(targetChain), - mintRecipient, - token, - getRegisteredEmitter(targetChain) - ); - } +Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ +--- BEGIN CONTENT --- +--- +title: Get Started with Token Bridge +description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. +categories: Token-Bridge, Transfer +--- - function custodyTokens( - address token, - uint256 amount - ) internal returns (uint256) { - // query own token balance before transfer - (, bytes memory queriedBalanceBefore) = token.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) - ); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); +# Token Bridge - // deposit tokens - SafeERC20.safeTransferFrom( - IERC20(token), - msg.sender, - address(this), - amount - ); +## Introduction - // query own token balance after transfer - (, bytes memory queriedBalanceAfter) = token.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) - ); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. - return balanceAfter - balanceBefore; - } +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. - /** - * @notice `redeemTokensWithPayload` verifies the Wormhole message from the source chain and - * verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge - * contract by passing the Circle message and attestation to mint tokens to the specified - * mint recipient. It also verifies that the caller is the specified mint recipient to ensure - * atomic execution of the additional instructions in the Wormhole message. - * @dev reverts if: - * - Wormhole message is not properly attested - * - Wormhole message was not emitted from a registered contrat - * - Wormhole message was already consumed by this contract - * - msg.sender is not the encoded mintRecipient - * - Circle Bridge message and Wormhole message are not associated - * - `receiveMessage` call to Circle Transmitter fails - * @param params Struct containing the following attributes: - * - `encodedWormholeMessage` Wormhole message emitted by a registered contract including - * information regarding the token burn on the source chain and an arbitrary message. - * - `circleBridgeMessage` Message emitted by Circle Bridge contract with information regarding - * the token burn on the source chain. - * - `circleAttestation` Serialized EC Signature attesting the cross-chain transfer - * @return depositInfo Struct containing the following attributes: - * - `token` Address (bytes32 left-zero-padded) of token to be minted - * - `amount` Amount of tokens to be minted - * - `sourceDomain` Circle domain for the source chain - * - `targetDomain` Circle domain for the target chain - * - `nonce` Circle sequence number for the transfer - * - `fromAddress` Source CircleIntegration contract caller's address - * - `mintRecipient` Recipient of minted tokens (must be caller of this contract) - * - `payload` Arbitrary Wormhole message payload - */ - function redeemTokensWithPayload( - RedeemParameters calldata params - ) public returns (DepositWithPayload memory depositInfo) { - // verify the wormhole message - IWormhole.VM memory verifiedMessage = verifyWormholeRedeemMessage( - params.encodedWormholeMessage - ); +## Prerequisites - // Decode the message payload into the DepositWithPayload struct. Call the Circle TokenMinter - // contract to determine the address of the encoded token on this chain. - depositInfo = decodeDepositWithPayload(verifiedMessage.payload); - depositInfo.token = fetchLocalTokenAddress( - depositInfo.sourceDomain, - depositInfo.token - ); +To interact with the Wormhole Token Bridge, you'll need the following: - // confirm that circle gave us a valid token address - require(depositInfo.token != bytes32(0), "invalid local token address"); +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers - // confirm that the caller is the `mintRecipient` to ensure atomic execution - require( - addressToBytes32(msg.sender) == depositInfo.mintRecipient, - "caller must be mintRecipient" - ); +## How to Interact with Token Bridge Contracts - // confirm that the caller passed the correct message pair - require( - verifyCircleMessage( - params.circleBridgeMessage, - depositInfo.sourceDomain, - depositInfo.targetDomain, - depositInfo.nonce - ), - "invalid message pair" - ); +The primary functions of the Token Bridge contracts revolve around: - // call the circle bridge to mint tokens to the recipient - bool success = circleTransmitter().receiveMessage( - params.circleBridgeMessage, - params.circleAttestation - ); - require(success, "CIRCLE_INTEGRATION: failed to mint tokens"); +- **Attesting a token** - registering a new token for cross-chain transfers +- **Transferring tokens** - locking and minting tokens across chains +- **Transferring tokens with a payload** - including additional data with transfers - // emit Redeemed event - emit Redeemed( - verifiedMessage.emitterChainId, - verifiedMessage.emitterAddress, - verifiedMessage.sequence - ); - } +### Attest a token - function verifyWormholeRedeemMessage( - bytes memory encodedMessage - ) internal returns (IWormhole.VM memory) { - require(evmChain() == block.chainid, "invalid evm chain"); +Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. - // parse and verify the Wormhole core message - ( - IWormhole.VM memory verifiedMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); +The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. - // confirm that the core layer verified the message - require(valid, reason); +```solidity +function attestToken( + address tokenAddress, + uint32 nonce +) external payable returns (uint64 sequence); +``` - // verify that this message was emitted by a trusted contract - require(verifyEmitter(verifiedMessage), "unknown emitter"); +??? interface "Parameters" - // revert if this message has been consumed already - require( - !isMessageConsumed(verifiedMessage.hash), - "message already consumed" - ); - consumeMessage(verifiedMessage.hash); + `tokenAddress` ++"address"++ + + The contract address of the token to be attested. - return verifiedMessage; - } + --- - function verifyEmitter( - IWormhole.VM memory vm - ) internal view returns (bool) { - // verify that the sender of the wormhole message is a trusted - return (getRegisteredEmitter(vm.emitterChainId) == vm.emitterAddress && - vm.emitterAddress != bytes32(0)); - } + `nonce` ++"uint32"++ - function verifyCircleMessage( - bytes memory circleMessage, - uint32 sourceDomain, - uint32 targetDomain, - uint64 nonce - ) internal pure returns (bool) { - // parse the circle bridge message inline - uint32 circleSourceDomain = circleMessage.toUint32(4); - uint32 circleTargetDomain = circleMessage.toUint32(8); - uint64 circleNonce = circleMessage.toUint64(12); + An arbitrary value provided by the caller to ensure uniqueness. - // confirm that both the Wormhole message and Circle message share the same transfer info - return (sourceDomain == circleSourceDomain && - targetDomain == circleTargetDomain && - nonce == circleNonce); - } +??? interface "Returns" - /** - * @notice Fetches the local token address given an address and domain from - * a different chain. - * @param sourceDomain Circle domain for the sending chain. - * @param sourceToken Address of the token for the sending chain. - * @return Address bytes32 formatted address of the `sourceToken` on this chain. - */ - function fetchLocalTokenAddress( - uint32 sourceDomain, - bytes32 sourceToken - ) public view returns (bytes32) { - return - addressToBytes32( - circleTokenMinter().remoteTokensToLocalTokens( - keccak256(abi.encodePacked(sourceDomain, sourceToken)) - ) - ); - } + `sequence` ++"uint64"++ + + A unique identifier for the attestation transaction. - /** - * @notice Converts type address to bytes32 (left-zero-padded) - * @param address_ Address to convert to bytes32 - * @return Address bytes32 - */ - function addressToBytes32(address address_) public pure returns (bytes32) { - return bytes32(uint256(uint160(address_))); - } -} - ``` +When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. -The functions provided by the Circle Integration contract are as follows: +You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. -- **`transferTokensWithPayload`** - calls the Circle Bridge contract to burn Circle-supported tokens. It emits a Wormhole message containing a user-specified payload with instructions for what to do with the Circle-supported assets once they have been minted on the target chain +### Transfer Tokens - ??? interface "Parameters" +Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. - `transferParams` ++"TransferParameters"++ +Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. - A tuple containing the parameters for the transfer. +```solidity +function transferTokens( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint256 arbiterFee, + uint32 nonce +) external payable returns (uint64 sequence); +``` - ??? child "`TransferParameters` struct" +??? interface "Parameters" - `token` ++"address"++ + `token` ++"address"++ + + The address of the token being transferred. - Address of the token to be burned. + --- - --- + `amount` ++"uint256"++ + The amount of tokens to be transferred. - `amount` ++"uint256"++ + --- - Amount of the token to be burned. + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. - --- + --- - `targetChain` ++"uint16"++ + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. - Wormhole chain ID of the target blockchain. + --- - --- + `arbiterFee` ++"uint256"++ + Optional fee to be paid to an arbiter for relaying the transfer. - `mintRecipient` ++"bytes32"++ + --- - The recipient wallet or contract address on the target chain. + `nonce` ++"uint32"++ + A unique identifier for the transaction. - --- +??? interface "Returns" - `batchId` ++"uint32"++ + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. - The ID for Wormhole message batching. +Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. - --- +```solidity +function completeTransfer(bytes memory encodedVm) external; +``` - `payload` ++"bytes"++ +??? interface "Parameters" - Arbitrary payload to be delivered to the target chain via Wormhole. + `encodedVm` ++"bytes memory"++ + + The signed VAA containing the transfer details. - ??? interface "Returns" +!!!note + - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation + - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain - `messageSequence` ++"uint64"++ +### Transfer tokens with payload - Wormhole sequence number for this contract. +While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. -- `redeemTokensWithPayload` - verifies the Wormhole message from the source chain and verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge contract by passing the Circle message and attestation to the `receiveMessage` function, which is responsible for minting tokens to the specified mint recipient. It also verifies that the caller is the specified mint recipient to ensure atomic execution of the additional instructions in the Wormhole message +Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. - ??? interface "Parameters" +```solidity +function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload +) external payable returns (uint64 sequence); +``` - `params` ++"RedeemParameters"++ +??? interface "Parameters" + + `token` ++"address"++ + + The address of the token being transferred. + + --- + + `amount` ++"uint256"++ + The amount of tokens to be transferred. + + --- + + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. + + --- + + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. + + --- + + `nonce` ++"uint32"++ + A unique identifier for the transaction. + + --- - A tuple containing the parameters for the redemption. + `payload` ++"bytes memory"++ + Arbitrary data payload attached to the transaction. - ??? child "`RedeemParameters` struct" +??? interface "Returns" + + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. - `encodedWormholeMessage` ++"bytes"++ +After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. - Wormhole message emitted by a registered contract including information regarding the token burn on the source chain and an arbitrary message. +Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. - --- +```solidity +function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); +``` - `circleBridgeMessage` ++"bytes"++ +??? interface "Parameters" - Message emitted by Circle Bridge contract with information regarding the token burn on the source chain. + `encodedVm` ++"bytes memory"++ - --- + The signed VAA containing the transfer details. - `circleAttestation` ++"bytes"++ +??? interface "Returns" - Serialized EC signature attesting the cross-chain transfer. + `bytes memory` - ??? interface "Returns" + The extracted payload data. - `depositInfo` ++"DepositWithPayload"++ +## Source Code References - Information about the deposit. +For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: - ??? child "`DepositWithPayload` struct" +- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} +- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} - `token` ++"bytes32"++ +## Portal Bridge - Address (`bytes32` left-zero-padded) of token to be minted. +A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/..learn/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- - `amount` ++"uint256"++ +# Glossary - Amount of tokens to be minted. - - --- +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - `sourceDomain` ++"uint32"++ +## Chain ID - Circle domain for the source chain. +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - --- +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - `targetDomain` ++"uint32"++ +## Consistency Level - Circle domain for the target chain. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - --- +## Delivery Provider - `nonce` ++"uint64"++ +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - Circle sequence number for the transfer. +## Emitter - --- +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - `fromAddress` ++"bytes32"++ +## Finality - Source Circle Integration contract caller's address. +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - --- +## Guardian - `mintRecipient` ++"bytes32"++ +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - Recipient of minted tokens (must be caller of this contract). +## Guardian Network - --- +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - `payload` ++"bytes"++ +## Guardian Set - Arbitrary Wormhole message payload. +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - ??? interface "Emits" +## Heartbeat - `Redeemed` - event emitted when Circle-supported assets have been minted to the `mintRecipient` +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - ??? child "Event arguments" +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - `emitterChainId` ++"uint16"++ +## Observation - Wormhole chain ID of emitter contract on source chain. +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - --- +## Relayer - `emitterAddress` ++"bytes32"++ +A relayer is any process that delivers VAAs to a destination. - Address (`bytes32` zero-left-padded) of emitter on source chain. +## Sequence - --- +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - `sequence` ++"uint64"++ +## Spy - Sequence of Wormhole message used to mint tokens. +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. -## Circle's CCTP Contracts +## VAA -Three key contracts power Circle's CCTP: +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. -- **`TokenMessenger`** - the entry point for cross-chain USDC transfers, routing messages to initiate USDC burns on the source chain, and mint USDC on the destination chain -- **`MessageTransmitter`** - handles generic message passing, sending messages from the source chain and receiving them on the destination chain -- **`TokenMinter`** - responsible for the actual minting and burning of USDC, utilizing chain-specific settings for both the burners and minters across different networks +## Validator -The following sections will examine these contracts in-depth, focusing on the methods invoked indirectly through function calls in the Wormhole Circle Integration contract. +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- -!!! note - When using Wormhole's CCTP integration, you will not directly interact with these contracts. You will indirectly interact with them through the Wormhole Circle Integration contract. +Doc-Content: https://wormhole.com/docs/..learn/governance/overview/ +--- BEGIN CONTENT --- +--- +title: MultiGov Overview +description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. +categories: MultiGov +--- -These contracts can be found in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/){target=\_blank} on GitHub. +# MultiGov: Cross-Chain Governance with Wormhole -### Token Messenger Contract +## Overview -The Token Messenger contract enables cross-chain USDC transfers by coordinating message exchanges between blockchains. It works alongside the Message Transmitter contract to relay messages for burning USDC on a source chain and minting it on a destination chain. The contract emits events to track both the burning of tokens and their subsequent minting on the destination chain. +### What Is MultiGov and Why Is It Important? -To ensure secure communication, the Token Messenger restricts message handling to registered remote Token Messenger contracts only. It verifies the proper conditions for token burning and manages local and remote minters using chain-specific settings. +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. -Additionally, the contract provides methods for updating or replacing previously sent burn messages, adding or removing remote Token Messenger contracts, and managing the minting process for cross-chain transfers. +MultiGov is important because it: -??? code "Token Messenger contract" - ```solidity - /* - * Copyright (c) 2022, Circle Internet Financial Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -pragma solidity 0.7.6; +- **Increases participation** by allowing token holders from multiple chains to engage in governance +- **Enhances security** by leveraging Wormhole's robust cross-chain communication +- **Improves scalability** by integrating any chain supported by Wormhole +- **Enables unified governance** and coordinated decision-making across multiple networks -import "./interfaces/IMessageHandler.sol"; -import "./interfaces/ITokenMinter.sol"; -import "./interfaces/IMintBurnToken.sol"; -import "./interfaces/IMessageTransmitter.sol"; -import "./messages/BurnMessage.sol"; -import "./messages/Message.sol"; -import "./roles/Rescuable.sol"; +### Key Features -/** - * @title TokenMessenger - * @notice Sends messages and receives messages to/from MessageTransmitters - * and to/from TokenMinters - */ -contract TokenMessenger is IMessageHandler, Rescuable { - // ============ Events ============ - /** - * @notice Emitted when a DepositForBurn message is sent - * @param nonce unique nonce reserved by message - * @param burnToken address of token burnt on source domain - * @param amount deposit amount - * @param depositor address where deposit is transferred from - * @param mintRecipient address receiving minted tokens on destination domain as bytes32 - * @param destinationDomain destination domain - * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32 - * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). - * If equal to bytes32(0), any address can call receiveMessage(). - */ - event DepositForBurn( - uint64 indexed nonce, - address indexed burnToken, - uint256 amount, - address indexed depositor, - bytes32 mintRecipient, - uint32 destinationDomain, - bytes32 destinationTokenMessenger, - bytes32 destinationCaller - ); +- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains +- **Cross-chain voting** - token holders on any integrated chain can cast votes +- **Vote aggregation** - votes from all chains are collected and tallied on the hub +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Wormhole integration** - secure and reliable cross-chain communication +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain - /** - * @notice Emitted when tokens are minted - * @param mintRecipient recipient address of minted tokens - * @param amount amount of minted tokens - * @param mintToken contract address of minted token - */ - event MintAndWithdraw( - address indexed mintRecipient, - uint256 amount, - address indexed mintToken - ); +### High-Level Architecture Diagram - /** - * @notice Emitted when a remote TokenMessenger is added - * @param domain remote domain - * @param tokenMessenger TokenMessenger on remote domain - */ - event RemoteTokenMessengerAdded(uint32 domain, bytes32 tokenMessenger); +The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. - /** - * @notice Emitted when a remote TokenMessenger is removed - * @param domain remote domain - * @param tokenMessenger TokenMessenger on remote domain - */ - event RemoteTokenMessengerRemoved(uint32 domain, bytes32 tokenMessenger); +For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. - /** - * @notice Emitted when the local minter is added - * @param localMinter address of local minter - * @notice Emitted when the local minter is added - */ - event LocalMinterAdded(address localMinter); + +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) +--- END CONTENT --- - /** - * @notice Emitted when the local minter is removed - * @param localMinter address of local minter - * @notice Emitted when the local minter is removed - */ - event LocalMinterRemoved(address localMinter); +Doc-Content: https://wormhole.com/docs/..learn/transfers/cctp/ +--- BEGIN CONTENT --- +--- +title: Circle's CCTP Bridge +description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. +categories: Transfer +--- - // ============ Libraries ============ - using TypedMemView for bytes; - using TypedMemView for bytes29; - using BurnMessage for bytes29; - using Message for bytes29; +# Circle's CCTP Bridge - // ============ State Variables ============ - // Local Message Transmitter responsible for sending and receiving messages to/from remote domains - IMessageTransmitter public immutable localMessageTransmitter; +Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. - // Version of message body format - uint32 public immutable messageBodyVersion; +While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: - // Minter responsible for minting and burning tokens on the local domain - ITokenMinter public localMinter; +- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves +- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain +- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer - // Valid TokenMessengers on remote domains - mapping(uint32 => bytes32) public remoteTokenMessengers; +!!! note + Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. - // ============ Modifiers ============ - /** - * @notice Only accept messages from a registered TokenMessenger contract on given remote domain - * @param domain The remote domain - * @param tokenMessenger The address of the TokenMessenger contract for the given remote domain - */ - modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) { - require( - _isRemoteTokenMessenger(domain, tokenMessenger), - "Remote TokenMessenger unsupported" - ); - _; - } +You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. - /** - * @notice Only accept messages from the registered message transmitter on local domain - */ - modifier onlyLocalMessageTransmitter() { - // Caller must be the registered message transmitter for this domain - require(_isLocalMessageTransmitter(), "Invalid message transmitter"); - _; - } +## Automatic Relaying - // ============ Constructor ============ - /** - * @param _messageTransmitter Message transmitter address - * @param _messageBodyVersion Message body version - */ - constructor(address _messageTransmitter, uint32 _messageBodyVersion) { - require( - _messageTransmitter != address(0), - "MessageTransmitter not set" - ); - localMessageTransmitter = IMessageTransmitter(_messageTransmitter); - messageBodyVersion = _messageBodyVersion; - } +To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. - // ============ External Functions ============ - /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. - * Emits a `DepositForBurn` event. - * @dev reverts if: - * - given burnToken is not supported - * - given destinationDomain has no TokenMessenger registered - * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance - * to this contract is less than `amount`. - * - burn() reverts. For example, if `amount` is 0. - * - MessageTransmitter returns false or reverts. - * @param amount amount of tokens to burn - * @param destinationDomain destination domain - * @param mintRecipient address of mint recipient on destination domain - * @param burnToken address of contract to burn deposited tokens, on local domain - * @return _nonce unique nonce reserved by message - */ - function depositForBurn( - uint256 amount, - uint32 destinationDomain, - bytes32 mintRecipient, - address burnToken - ) external returns (uint64 _nonce) { - return - _depositForBurn( - amount, - destinationDomain, - mintRecipient, - burnToken, - // (bytes32(0) here indicates that any address can call receiveMessage() - // on the destination domain, triggering mint to specified `mintRecipient`) - bytes32(0) - ); - } +This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. - /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint - * on the destination domain must be called by `destinationCaller`. - * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible - * to broadcast the message on the destination domain. This is an advanced feature, and the standard - * depositForBurn() should be preferred for use cases where a specific destination caller is not required. - * Emits a `DepositForBurn` event. - * @dev reverts if: - * - given destinationCaller is zero address - * - given burnToken is not supported - * - given destinationDomain has no TokenMessenger registered - * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance - * to this contract is less than `amount`. - * - burn() reverts. For example, if `amount` is 0. - * - MessageTransmitter returns false or reverts. - * @param amount amount of tokens to burn - * @param destinationDomain destination domain - * @param mintRecipient address of mint recipient on destination domain - * @param burnToken address of contract to burn deposited tokens, on local domain - * @param destinationCaller caller on the destination domain, as bytes32 - * @return nonce unique nonce reserved by message - */ - function depositForBurnWithCaller( - uint256 amount, - uint32 destinationDomain, - bytes32 mintRecipient, - address burnToken, - bytes32 destinationCaller - ) external returns (uint64 nonce) { - // Destination caller must be nonzero. To allow any destination caller, use depositForBurn(). - require(destinationCaller != bytes32(0), "Invalid destination caller"); +The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. - return - _depositForBurn( - amount, - destinationDomain, - mintRecipient, - burnToken, - destinationCaller - ); - } +| Chain | Fee | +|:---------------:|:---------------:| +| Ethereum | 1.0 USDC | +| Everything else | 0.1 USDC | - /** - * @notice Replace a BurnMessage to change the mint recipient and/or - * destination caller. Allows the sender of a previous BurnMessage - * (created by depositForBurn or depositForBurnWithCaller) - * to send a new BurnMessage to replace the original. - * The new BurnMessage will reuse the amount and burn token of the original, - * without requiring a new deposit. - * @dev The new message will reuse the original message's nonce. For a - * given nonce, all replacement message(s) and the original message are - * valid to broadcast on the destination domain, until the first message - * at the nonce confirms, at which point all others are invalidated. - * Note: The msg.sender of the replaced message must be the same as the - * msg.sender of the original message. - * @param originalMessage original message bytes (to replace) - * @param originalAttestation original attestation bytes - * @param newDestinationCaller the new destination caller, which may be the - * same as the original destination caller, a new destination caller, or an empty - * destination caller (bytes32(0), indicating that any destination caller is valid.) - * @param newMintRecipient the new mint recipient, which may be the same as the - * original mint recipient, or different. - */ - function replaceDepositForBurn( - bytes calldata originalMessage, - bytes calldata originalAttestation, - bytes32 newDestinationCaller, - bytes32 newMintRecipient - ) external { - bytes29 _originalMsg = originalMessage.ref(0); - _originalMsg._validateMessageFormat(); - bytes29 _originalMsgBody = _originalMsg._messageBody(); - _originalMsgBody._validateBurnMessageFormat(); + - bytes32 _originalMsgSender = _originalMsgBody._getMessageSender(); - // _originalMsgSender must match msg.sender of original message - require( - msg.sender == Message.bytes32ToAddress(_originalMsgSender), - "Invalid sender for message" - ); - require( - newMintRecipient != bytes32(0), - "Mint recipient must be nonzero" - ); +## Native Gas Drop Off - bytes32 _burnToken = _originalMsgBody._getBurnToken(); - uint256 _amount = _originalMsgBody._getAmount(); +Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. - bytes memory _newMessageBody = BurnMessage._formatMessage( - messageBodyVersion, - _burnToken, - newMintRecipient, - _amount, - _originalMsgSender - ); +The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. - localMessageTransmitter.replaceMessage( - originalMessage, - originalAttestation, - _newMessageBody, - newDestinationCaller - ); + +--- END CONTENT --- - emit DepositForBurn( - _originalMsg._nonce(), - Message.bytes32ToAddress(_burnToken), - _amount, - msg.sender, - newMintRecipient, - _originalMsg._destinationDomain(), - _originalMsg._recipient(), - newDestinationCaller - ); - } +Doc-Content: https://wormhole.com/docs/..learn/transfers/ +--- BEGIN CONTENT --- +--- +title: Multichain Transfers +description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. +categories: Transfer +--- - /** - * @notice Handles an incoming message received by the local MessageTransmitter, - * and takes the appropriate action. For a burn message, mints the - * associated token to the requested recipient on the local domain. - * @dev Validates the local sender is the local MessageTransmitter, and the - * remote sender is a registered remote TokenMessenger for `remoteDomain`. - * @param remoteDomain The domain where the message originated from. - * @param sender The sender of the message (remote TokenMessenger). - * @param messageBody The message body bytes. - * @return success Bool, true if successful. - */ - function handleReceiveMessage( - uint32 remoteDomain, - bytes32 sender, - bytes calldata messageBody - ) - external - override - onlyLocalMessageTransmitter - onlyRemoteTokenMessenger(remoteDomain, sender) - returns (bool) - { - bytes29 _msg = messageBody.ref(0); - _msg._validateBurnMessageFormat(); - require( - _msg._getVersion() == messageBodyVersion, - "Invalid message body version" - ); +# Multichain Transfers - bytes32 _mintRecipient = _msg._getMintRecipient(); - bytes32 _burnToken = _msg._getBurnToken(); - uint256 _amount = _msg._getAmount(); +These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. - ITokenMinter _localMinter = _getLocalMinter(); +Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: - _mintAndWithdraw( - address(_localMinter), - remoteDomain, - _burnToken, - Message.bytes32ToAddress(_mintRecipient), - _amount - ); +- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset +- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism - return true; - } +## Compare Transfer Products - /** - * @notice Add the TokenMessenger for a remote domain. - * @dev Reverts if there is already a TokenMessenger set for domain. - * @param domain Domain of remote TokenMessenger. - * @param tokenMessenger Address of remote TokenMessenger as bytes32. - */ - function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) - external - onlyOwner - { - require(tokenMessenger != bytes32(0), "bytes32(0) not allowed"); +A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: - require( - remoteTokenMessengers[domain] == bytes32(0), - "TokenMessenger already set" - ); +### NTT vs. Token Bridge - remoteTokenMessengers[domain] = tokenMessenger; - emit RemoteTokenMessengerAdded(domain, tokenMessenger); - } +Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. - /** - * @notice Remove the TokenMessenger for a remote domain. - * @dev Reverts if there is no TokenMessenger set for `domain`. - * @param domain Domain of remote TokenMessenger - */ - function removeRemoteTokenMessenger(uint32 domain) external onlyOwner { - // No TokenMessenger set for given remote domain. - require( - remoteTokenMessengers[domain] != bytes32(0), - "No TokenMessenger set" - ); +- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains +- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases - bytes32 _removedTokenMessenger = remoteTokenMessengers[domain]; - delete remoteTokenMessengers[domain]; - emit RemoteTokenMessengerRemoved(domain, _removedTokenMessenger); - } +
- /** - * @notice Add minter for the local domain. - * @dev Reverts if a minter is already set for the local domain. - * @param newLocalMinter The address of the minter on the local domain. - */ - function addLocalMinter(address newLocalMinter) external onlyOwner { - require(newLocalMinter != address(0), "Zero address not allowed"); +| Supports | NTT | Token Bridge | +|---------------------------|--------------------|--------------------| +| Message Payload | :white_check_mark: | :white_check_mark: | +| Wrapped Assets | :x: | :white_check_mark: | +| Native Assets | :white_check_mark: | :x: | +| Contract-Free Development | :x: | :white_check_mark: | +| User-Owned Contracts | :white_check_mark: | :x: | - require( - address(localMinter) == address(0), - "Local minter is already set." - ); +
- localMinter = ITokenMinter(newLocalMinter); +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: - emit LocalMinterAdded(newLocalMinter); - } +
- /** - * @notice Remove the minter for the local domain. - * @dev Reverts if the minter of the local domain is not set. - */ - function removeLocalMinter() external onlyOwner { - address _localMinterAddress = address(localMinter); - require(_localMinterAddress != address(0), "No local minter is set."); - delete localMinter; - emit LocalMinterRemoved(_localMinterAddress); - } +### Settlement - // ============ Internal Utils ============ - /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. - * Emits a `DepositForBurn` event. - * @param _amount amount of tokens to burn (must be non-zero) - * @param _destinationDomain destination domain - * @param _mintRecipient address of mint recipient on destination domain - * @param _burnToken address of contract to burn deposited tokens, on local domain - * @param _destinationCaller caller on the destination domain, as bytes32 - * @return nonce unique nonce reserved by message - */ - function _depositForBurn( - uint256 _amount, - uint32 _destinationDomain, - bytes32 _mintRecipient, - address _burnToken, - bytes32 _destinationCaller - ) internal returns (uint64 nonce) { - require(_amount > 0, "Amount must be nonzero"); - require(_mintRecipient != bytes32(0), "Mint recipient must be nonzero"); +Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. - bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger( - _destinationDomain - ); +By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. - ITokenMinter _localMinter = _getLocalMinter(); - IMintBurnToken _mintBurnToken = IMintBurnToken(_burnToken); - require( - _mintBurnToken.transferFrom( - msg.sender, - address(_localMinter), - _amount - ), - "Transfer operation failed" - ); - _localMinter.burn(_burnToken, _amount); +## Additional Resources - // Format message body - bytes memory _burnMessage = BurnMessage._formatMessage( - messageBodyVersion, - Message.addressToBytes32(_burnToken), - _mintRecipient, - _amount, - Message.addressToBytes32(msg.sender) - ); +
- uint64 _nonceReserved = _sendDepositForBurnMessage( - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller, - _burnMessage - ); +- :octicons-tools-16:{ .lg .middle } **Product Comparison** - emit DepositForBurn( - _nonceReserved, - _burnToken, - _amount, - msg.sender, - _mintRecipient, - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller - ); + --- - return _nonceReserved; - } + Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - /** - * @notice Sends a BurnMessage through the local message transmitter - * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0), - * or else calls sendMessageWithCaller(). - * @param _destinationDomain destination domain - * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32 - * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0), - * any address can call receiveMessage() on destination domain. - * @param _burnMessage formatted BurnMessage bytes (message body) - * @return nonce unique nonce reserved by message - */ - function _sendDepositForBurnMessage( - uint32 _destinationDomain, - bytes32 _destinationTokenMessenger, - bytes32 _destinationCaller, - bytes memory _burnMessage - ) internal returns (uint64 nonce) { - if (_destinationCaller == bytes32(0)) { - return - localMessageTransmitter.sendMessage( - _destinationDomain, - _destinationTokenMessenger, - _burnMessage - ); - } else { - return - localMessageTransmitter.sendMessageWithCaller( - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller, - _burnMessage - ); - } - } + [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) - /** - * @notice Mints tokens to a recipient - * @param _tokenMinter address of TokenMinter contract - * @param _remoteDomain domain where burned tokens originate from - * @param _burnToken address of token burned - * @param _mintRecipient recipient address of minted tokens - * @param _amount amount of minted tokens - */ - function _mintAndWithdraw( - address _tokenMinter, - uint32 _remoteDomain, - bytes32 _burnToken, - address _mintRecipient, - uint256 _amount - ) internal { - ITokenMinter _minter = ITokenMinter(_tokenMinter); - address _mintToken = _minter.mint( - _remoteDomain, - _burnToken, - _mintRecipient, - _amount - ); +- :octicons-book-16:{ .lg .middle } **Use Cases** - emit MintAndWithdraw(_mintRecipient, _amount, _mintToken); - } + --- - /** - * @notice return the remote TokenMessenger for the given `_domain` if one exists, else revert. - * @param _domain The domain for which to get the remote TokenMessenger - * @return _tokenMessenger The address of the TokenMessenger on `_domain` as bytes32 - */ - function _getRemoteTokenMessenger(uint32 _domain) - internal - view - returns (bytes32) - { - bytes32 _tokenMessenger = remoteTokenMessengers[_domain]; - require(_tokenMessenger != bytes32(0), "No TokenMessenger for domain"); - return _tokenMessenger; - } + Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - /** - * @notice return the local minter address if it is set, else revert. - * @return local minter as ITokenMinter. - */ - function _getLocalMinter() internal view returns (ITokenMinter) { - require(address(localMinter) != address(0), "Local minter is not set"); - return localMinter; - } + [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) - /** - * @notice Return true if the given remote domain and TokenMessenger is registered - * on this TokenMessenger. - * @param _domain The remote domain of the message. - * @param _tokenMessenger The address of the TokenMessenger on remote domain. - * @return true if a remote TokenMessenger is registered for `_domain` and `_tokenMessenger`, - * on this TokenMessenger. - */ - function _isRemoteTokenMessenger(uint32 _domain, bytes32 _tokenMessenger) - internal - view - returns (bool) - { - return - _tokenMessenger != bytes32(0) && - remoteTokenMessengers[_domain] == _tokenMessenger; - } - /** - * @notice Returns true if the message sender is the local registered MessageTransmitter - * @return true if message sender is the registered local message transmitter - */ - function _isLocalMessageTransmitter() internal view returns (bool) { - return - address(localMessageTransmitter) != address(0) && - msg.sender == address(localMessageTransmitter); - } -} - ``` +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers - Deployment Models +description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. +categories: NTT, Transfer +--- + +# Deployment Models - This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol){target=\_blank} on GitHub. +The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. -The functions provided by the Token Messenger contract are as follows: +## Hub-and-Spoke -- **`depositForBurn`** - deposits and burns tokens from the sender to be minted on the destination domain. Minted tokens will be transferred to `mintRecipient` +The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - ??? interface "Parameters" +This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - `amount` ++"uint256"++ - - The amount of tokens to burn. +- **Hub chain** - tokens are locked when initiating a transfer +- **Spoke chains** - Equivalent tokens are minted on the destination chain - --- +When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - `destinationDomain` ++"uint32"++ - - The network where the token will be minted after burn. +## Burn-and-Mint - --- +The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - `mintRecipient` ++"bytes32"++ - - Address of mint recipient on destination domain. +This model best suits new token deployments or projects willing to upgrade existing contracts. - --- +- **Source chain** - tokens are burned when initiating a transfer +- **Destination chain** - equivalent tokens are minted on the destination chain +--- END CONTENT --- - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. +Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Overview +description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. +categories: NTT, Transfer +--- - ??? interface "Returns" +# Native Token Transfers - `_nonce` ++"uint64"++ - - Unique nonce reserved by message. +!!!tip "Looking to deploy NTT?" + If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - ??? interface "Emits" + - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - `DepositForBurn` - event emitted when `depositForBurn` is called. The `destinationCaller` is set to `bytes32(0)` to allow any address to call `receiveMessage` on the destination domain +## Introduction - ??? child "Event Arguments" +Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. - --- +## Key Features - `burnToken` ++"address"++ - - Address of token burnt on source domain. +Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: - --- +- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens +- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience +- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk +- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts +- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains +- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted +- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner +- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols +- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - `amount` ++"uint256"++ - - The deposit amount. +## Integration Paths - --- +Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. - `depositor` ++"address"++ - - Address where deposit is transferred from. +### Native Token Transfers Framework - --- +The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model +- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant +- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain +- **Token contracts** - native contracts owned by your protocol governance +- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - --- +The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: - `destinationDomain` ++"uint32"++ - - - Destination domain. +- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} +- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} - --- +### Token Bridge - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- +The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. +- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract +- **Security** - preconfigured rate limiting and integrated Global Accountant +- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} +- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process +- **Integration** - straightforward and permissionless method to deploy on multiple chains -- **`depositForBurnWithCaller`** - deposits and burns tokens from the sender to be minted on the destination domain. This method differs from `depositForBurn` in that the mint on the destination domain can only be called by the designated `destinationCaller` address +!!! note + [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. - ??? interface "Parameters" +## Supported Token Standards - `amount` ++"uint256"++ - - The amount of tokens to burn. +Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Overview +description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +categories: Settlement, Transfer +--- - `destinationDomain` ++"uint32"++ - - The network where the token will be minted after burn. +# Wormhole Settlement Overview - --- +## Introduction - `mintRecipient` ++"bytes32"++ - - Address of mint recipient on destination domain. +Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - --- +With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. +The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - --- +Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - `destinationCaller` ++"bytes32"++ - - Address of the caller on the destination domain who will trigger the mint. +## Key Features - ??? interface "Returns" +- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well +- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency +- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - `_nonce` ++"uint64"++ - - Unique nonce reserved by message. +## Integrator Paths - ??? interface "Emits" +### SDK Integrators - `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called +Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - ??? child "Event Arguments" +### NTT Integrators - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - --- +### Chain Integrators - `burnToken` ++"address"++ - - Address of token burnt on source domain. +Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - --- +!!!tip + Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - `amount` ++"uint256"++ - - The deposit amount. +## Related Resources - --- +- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page +--- END CONTENT --- - `depositor` ++"address"++ - - Address where deposit is transferred from. +Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ +--- BEGIN CONTENT --- +--- +title: Token Bridge +description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. +categories: Token-Bridge, Transfer +--- - --- +# Token Bridge - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - --- +Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - `destinationDomain` ++"uint32"++ - - - Destination domain. +Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - --- +This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- +### How Does It Work? - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. +At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. -- **`replaceDepositForBurn`** — replaces a previous `BurnMessage` to modify the mint recipient and/or the destination caller. The replacement message reuses the `_nonce` created by the original message, which allows the original message's sender to update the details without requiring a new deposit +Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - ??? interface "Parameters" +While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - `originalMessage` ++"bytes"++ - - The original burn message to be replaced. +In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). + +### Token Transfer Flow + +The transfer process is simple yet secure, involving a few key steps: + +1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message +4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody + +![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) + +### Key Features of the Token Bridge - --- +The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - `originalAttestation` ++"bytes"++ - - The attestation of the original message. +The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - --- +### Message and Payload Structure - `newDestinationCaller` ++"bytes32"++ - - The new caller on the destination domain, can be the same or updated. +To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - --- +- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens +- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain +- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name +- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain +- `UpgradeContract` - upgrade the contract - `newMintRecipient` ++"bytes32"++ - - The new recipient for the minted tokens, can be the same or updated. +Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - ??? interface "Returns" +One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - None. +### Security and Authorization - ??? interface "Emits" +The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - `DepositForBurn` - event emitted when `replaceDepositForBurn` is called. Note that the `destinationCaller` will reflect the new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid +The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - ??? child "Event Arguments" +### Portal Bridge - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/concepts/integration/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - `burnToken` ++"address"++ - - Address of token burnt on source domain. +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/transfer-usdc/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - `amount` ++"uint256"++ - - The deposit amount. +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ +--- BEGIN CONTENT --- +--- +title: Complete USDC Transfer Flow +description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +--- - `depositor` ++"address"++ - - Address where deposit is transferred from. +# Complete USDC Transfer Flow - --- +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +## Introduction - --- +In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. - `destinationDomain` ++"uint32"++ - - - Destination domain. +Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. - --- +Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- +In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. +## Core Concepts -- **`handleReceiveMessage`** - handles an incoming message received by the local `MessageTransmitter` and takes the appropriate action. For a burn message, it mints the associated token to the requested recipient on the local domain. +When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: - ???+ note + - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain - Though this function can only be called by the local `MessageTransmitter`, it is included here as it emits the essential event for minting tokens and withdrawing to send to the recipient. + - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you - ??? interface "Parameters" +## Prerequisites - `remoteDomain` ++"uint32"++ - - The domain where the message originated. +Before you begin, ensure you have the following: - --- + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples + - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees - `sender` ++"bytes32"++ - - The address of the sender of the message. +## Supported Chains - --- +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. - `messageBody` ++"bytes"++ - - The bytes making up the body of the message. +## Project Setup - ??? interface "Returns" +In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. - `success` ++"boolean"++ - - Returns `true` if successful, otherwise, it returns `false`. +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project - ??? interface "Emits" + ```bash + mkdir cctp-circle + cd cctp-circle + npm init -y + ``` - `MintAndWithdraw` - event emitted when tokens are minted +2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries - ??? child "Event arguments" + ```bash + npm install @wormhole-foundation/sdk dotenv + ``` - `localMinter` ++"address"++ - - Minter responsible for minting and burning tokens on the local domain. +3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project - --- + ```bash + touch .env + ``` - `remoteDomain` ++"uint32"++ - - The domain where the message originated from. + Inside the `.env` file, add your private key - --- + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + ``` - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. + !!! note + Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. - --- +4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays - `mintRecipient` ++"address"++ - - Recipient address of minted tokens (indexed). + 1. Create the helpers file - --- + ```bash + mkdir helpers + touch helpers/helpers.ts + ``` - `amount` ++"uint256"++ - - Amount of minted tokens. + 2. Open the `helpers.ts` file and add the following code -### Message Transmitter Contract + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { config } from 'dotenv'; +config(); -The Message Transmitter contract ensures secure messaging across blockchain domains by managing message dispatch and tracking communication with events like `MessageSent` and `MessageReceived`. It uses a unique nonce for each message, which ensures proper validation, verifies attestation signatures, and prevents replay attacks. +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} -The contract supports flexible delivery options, allowing messages to be sent to a specific `destinationCaller` or broadcast more generally. It also includes domain-specific configurations to manage communication between chains. +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} -Additional features include replacing previously sent messages, setting maximum message body sizes, and verifying that messages are received only once per nonce to maintain network integrity. +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; -??? code "Message Transmitter contract" - ```solidity - /* - * Copyright (c) 2022, Circle Internet Financial Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -pragma solidity 0.7.6; + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } -import "@memview-sol/contracts/TypedMemView.sol"; -import "./interfaces/IMessageTransmitter.sol"; -import "./interfaces/IMessageHandler.sol"; -import "./messages/Message.sol"; -import "./roles/Pausable.sol"; -import "./roles/Rescuable.sol"; -import "./roles/Attestable.sol"; + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file -/** - * @title MessageTransmitter - * @notice Contract responsible for sending and receiving messages across chains. - */ -contract MessageTransmitter is - IMessageTransmitter, - Pausable, - Rescuable, - Attestable -{ - // ============ Events ============ - /** - * @notice Emitted when a new message is dispatched - * @param message Raw bytes of message - */ - event MessageSent(bytes message); +5. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains - /** - * @notice Emitted when a new message is received - * @param caller Caller (msg.sender) on destination domain - * @param sourceDomain The source domain this message originated from - * @param nonce The nonce unique to this message - * @param sender The sender of this message - * @param messageBody message body bytes - */ - event MessageReceived( - address indexed caller, - uint32 sourceDomain, - uint64 indexed nonce, - bytes32 sender, - bytes messageBody - ); + 1. Create the `manual-transfer.ts` file in the `src` directory - /** - * @notice Emitted when max message body size is updated - * @param newMaxMessageBodySize new maximum message body size, in bytes - */ - event MaxMessageBodySizeUpdated(uint256 newMaxMessageBodySize); + ```bash + touch src/manual-transfer.ts + ``` - // ============ Libraries ============ - using TypedMemView for bytes; - using TypedMemView for bytes29; - using Message for bytes29; + 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files - // ============ State Variables ============ - // Domain of chain on which the contract is deployed - uint32 public immutable localDomain; + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; + ``` - // Message Format version - uint32 public immutable version; + - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more + - **`solana`** - this adds support for Solana, a non-EVM chain + - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions - // Maximum size of message body, in bytes. - // This value is set by owner. - uint256 public maxMessageBodySize; +## Manual Transfers - // Next available nonce from this source domain - uint64 public nextAvailableNonce; +In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. - // Maps a bytes32 hash of (sourceDomain, nonce) -> uint256 (0 if unused, 1 if used) - mapping(bytes32 => uint256) public usedNonces; +This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. - // ============ Constructor ============ - constructor( - uint32 _localDomain, - address _attester, - uint32 _maxMessageBodySize, - uint32 _version - ) Attestable(_attester) { - localDomain = _localDomain; - maxMessageBodySize = _maxMessageBodySize; - version = _version; - } +### Set Up the Transfer Environment - // ============ External Functions ============ - /** - * @notice Send the message to the destination domain and recipient - * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. - * @param destinationDomain Domain of destination chain - * @param recipient Address of message recipient on destination chain as bytes32 - * @param messageBody Raw bytes content of message - * @return nonce reserved by message - */ - function sendMessage( - uint32 destinationDomain, - bytes32 recipient, - bytes calldata messageBody - ) external override whenNotPaused returns (uint64) { - bytes32 _emptyDestinationCaller = bytes32(0); - uint64 _nonce = _reserveAndIncrementNonce(); - bytes32 _messageSender = Message.addressToBytes32(msg.sender); +#### Configure Transfer Details - _sendMessage( - destinationDomain, - recipient, - _emptyDestinationCaller, - _messageSender, - _nonce, - messageBody - ); +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. - return _nonce; - } +1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed - /** - * @notice Replace a message with a new message body and/or destination caller. - * @dev The `originalAttestation` must be a valid attestation of `originalMessage`. - * Reverts if msg.sender does not match sender of original message, or if the source domain of the original message - * does not match this MessageTransmitter's local domain. - * @param originalMessage original message to replace - * @param originalAttestation attestation of `originalMessage` - * @param newMessageBody new message body of replaced message - * @param newDestinationCaller the new destination caller, which may be the - * same as the original destination caller, a new destination caller, or an empty - * destination caller (bytes32(0), indicating that any destination caller is valid.) - */ - function replaceMessage( - bytes calldata originalMessage, - bytes calldata originalAttestation, - bytes calldata newMessageBody, - bytes32 newDestinationCaller - ) external override whenNotPaused { - // Validate each signature in the attestation - _verifyAttestationSignatures(originalMessage, originalAttestation); + ```typescript + const wh = await wormhole('Testnet', [evm, solana]); + ``` + + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. - bytes29 _originalMsg = originalMessage.ref(0); +2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them - // Validate message format - _originalMsg._validateMessageFormat(); + ```typescript + const rcvChain = wh.getChain('Sepolia'); + ``` - // Validate message sender - bytes32 _sender = _originalMsg._sender(); - require( - msg.sender == Message.bytes32ToAddress(_sender), - "Sender not permitted to use nonce" - ); +3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains - // Validate source domain - uint32 _sourceDomain = _originalMsg._sourceDomain(); - require( - _sourceDomain == localDomain, - "Message not originally sent from this domain" - ); + ```typescript + const destination = await getSigner(rcvChain); + ``` - uint32 _destinationDomain = _originalMsg._destinationDomain(); - bytes32 _recipient = _originalMsg._recipient(); - uint64 _nonce = _originalMsg._nonce(); +4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK - _sendMessage( - _destinationDomain, - _recipient, - newDestinationCaller, - _sender, - _nonce, - newMessageBody - ); - } + ```typescript + + ``` - /** - * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the - * destination domain. - * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. - * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible - * to broadcast the message on the destination domain. This is an advanced feature, and the standard - * sendMessage() should be preferred for use cases where a specific destination caller is not required. - * @param destinationDomain Domain of destination chain - * @param recipient Address of message recipient on destination domain as bytes32 - * @param destinationCaller caller on the destination domain, as bytes32 - * @param messageBody Raw bytes content of message - * @return nonce reserved by message - */ - function sendMessageWithCaller( - uint32 destinationDomain, - bytes32 recipient, - bytes32 destinationCaller, - bytes calldata messageBody - ) external override whenNotPaused returns (uint64) { - require( - destinationCaller != bytes32(0), - "Destination caller must be nonzero" - ); +5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself - uint64 _nonce = _reserveAndIncrementNonce(); - bytes32 _messageSender = Message.addressToBytes32(msg.sender); + ```typescript + + ``` - _sendMessage( - destinationDomain, - recipient, - destinationCaller, - _messageSender, - _nonce, - messageBody - ); +#### Initiate the Transfer - return _nonce; - } +To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. - /** - * @notice Receive a message. Messages with a given nonce - * can only be broadcast once for a (sourceDomain, destinationDomain) - * pair. The message body of a valid message is passed to the - * specified recipient for further processing. - * - * @dev Attestation format: - * A valid attestation is the concatenated 65-byte signature(s) of exactly - * `thresholdSignature` signatures, in increasing order of attester address. - * ***If the attester addresses recovered from signatures are not in - * increasing order, signature verification will fail.*** - * If incorrect number of signatures or duplicate signatures are supplied, - * signature verification will fail. - * - * Message format: - * Field Bytes Type Index - * version 4 uint32 0 - * sourceDomain 4 uint32 4 - * destinationDomain 4 uint32 8 - * nonce 8 uint64 12 - * sender 32 bytes32 20 - * recipient 32 bytes32 52 - * messageBody dynamic bytes 84 - * @param message Message bytes - * @param attestation Concatenated 65-byte signature(s) of `message`, in increasing order - * of the attester address recovered from signatures. - * @return success bool, true if successful - */ - function receiveMessage(bytes calldata message, bytes calldata attestation) - external - override - whenNotPaused - returns (bool success) - { - // Validate each signature in the attestation - _verifyAttestationSignatures(message, attestation); +1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself + + ```typescript + amt, + source.address, + destination.address, + automatic + ); + ``` - bytes29 _msg = message.ref(0); +2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer - // Validate message format - _msg._validateMessageFormat(); + ```typescript + console.log(`Started Transfer: `, srcTxids); + ``` - // Validate domain - require( - _msg._destinationDomain() == localDomain, - "Invalid destination domain" - ); +#### Fetch the Circle Attestation (VAA) - // Validate destination caller - if (_msg._destinationCaller() != bytes32(0)) { - require( - _msg._destinationCaller() == - Message.addressToBytes32(msg.sender), - "Invalid caller for message" - ); - } +Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. - // Validate version - require(_msg._version() == version, "Invalid message version"); - // Validate nonce is available - uint32 _sourceDomain = _msg._sourceDomain(); - uint64 _nonce = _msg._nonce(); - bytes32 _sourceAndNonce = _hashSourceAndNonce(_sourceDomain, _nonce); - require(usedNonces[_sourceAndNonce] == 0, "Nonce already used"); - // Mark nonce used - usedNonces[_sourceAndNonce] = 1; +1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds - // Handle receive message - bytes32 _sender = _msg._sender(); - bytes memory _messageBody = _msg._messageBody().clone(); - require( - IMessageHandler(Message.bytes32ToAddress(_msg._recipient())) - .handleReceiveMessage(_sourceDomain, _sender, _messageBody), - "handleReceiveMessage() failed" - ); + ```typescript + + ``` - // Emit MessageReceived event - emit MessageReceived( - msg.sender, - _sourceDomain, - _nonce, - _sender, - _messageBody - ); - return true; - } +2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout - /** - * @notice Sets the max message body size - * @dev This value should not be reduced without good reason, - * to avoid impacting users who rely on large messages. - * @param newMaxMessageBodySize new max message body size, in bytes - */ - function setMaxMessageBodySize(uint256 newMaxMessageBodySize) - external - onlyOwner - { - maxMessageBodySize = newMaxMessageBodySize; - emit MaxMessageBodySizeUpdated(maxMessageBodySize); - } + ```typescript + console.log(`Got Attestation: `, attestIds); + ``` - // ============ Internal Utils ============ - /** - * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0), - * the message can only be received on the destination chain when called by `_destinationCaller`. - * @dev Format the message and emit `MessageSent` event with message information. - * @param _destinationDomain Domain of destination chain - * @param _recipient Address of message recipient on destination domain as bytes32 - * @param _destinationCaller caller on the destination domain, as bytes32 - * @param _sender message sender, as bytes32 - * @param _nonce nonce reserved for message - * @param _messageBody Raw bytes content of message - */ - function _sendMessage( - uint32 _destinationDomain, - bytes32 _recipient, - bytes32 _destinationCaller, - bytes32 _sender, - uint64 _nonce, - bytes calldata _messageBody - ) internal { - // Validate message body length - require( - _messageBody.length <= maxMessageBodySize, - "Message body exceeds max size" - ); + The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain - require(_recipient != bytes32(0), "Recipient must be nonzero"); +#### Complete the Transfer on the Destination Chain - // serialize message - bytes memory _message = Message._formatMessage( - version, - localDomain, - _destinationDomain, - _nonce, - _sender, - _recipient, - _destinationCaller, - _messageBody - ); +Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. - // Emit MessageSent event - emit MessageSent(_message); - } +Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain - /** - * @notice hashes `_source` and `_nonce`. - * @param _source Domain of chain where the transfer originated - * @param _nonce The unique identifier for the message from source to - destination - * @return hash of source and nonce - */ - function _hashSourceAndNonce(uint32 _source, uint64 _nonce) - internal - pure - returns (bytes32) - { - return keccak256(abi.encodePacked(_source, _nonce)); - } +```typescript +console.log(`Completed Transfer: `, dstTxids); - /** - * Reserve and increment next available nonce - * @return nonce reserved - */ - function _reserveAndIncrementNonce() internal returns (uint64) { - uint64 _nonceReserved = nextAvailableNonce; - nextAvailableNonce = nextAvailableNonce + 1; - return _nonceReserved; - } -} - ``` + console.log('Circle Transfer status: ', xfer); - This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol){target=\_blank} on GitHub. + process.exit(0); +``` -The functions provided by the Message Transmitter contract are as follows: +The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed -- **`receiveMessage`** — processes and validates an incoming message and its attestation. If valid, it triggers further action based on the message body +You can find the full code for the manual USDC transfer script below: - ??? interface "Parameters" +???- code "`manual-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; - `message` ++"bytes"++ - - The message to be processed, including details such as sender, recipient, and message body. +(async function () { + const wh = await wormhole('Testnet', [evm, solana]); - --- + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); - `attestation` ++"bytes"++ - - Concatenated 65-byte signature(s) that attest to the validity of the `message`. + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - ??? interface "Returns" + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; - `success` ++"boolean"++ - - Returns `true` if successful, otherwise, returns `false`. + const automatic = false; - ??? interface "Emits" + // Create the Circle transfer object + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); - `MessageReceived` - event emitted when a new message is received + console.log('Circle Transfer object created:', xfer); - ??? child "Event arguments" + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); - `caller` ++"address"++ - - Caller on destination domain. + // Wait for Circle Attestation (VAA) + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); - --- + // Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); - `sourceDomain` ++"uint32"++ - - The source domain this message originated from. + console.log('Circle Transfer status: ', xfer); - --- + process.exit(0); +})(); + ``` - `nonce` ++"uint64"++ - - Nonce unique to this message (indexed). +### Run Manual Transfer - --- +To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly - `sender` ++"bytes32"++ - - Sender of this message. +```bash +npx ts-node src/manual-transfer.ts +``` - --- +This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). - `messageBody` ++"bytes"++ - - The body of the message. +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. -- **`sendMessage`** — sends a message to the destination domain and recipient. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event +### Complete Partial Transfer - ??? interface "Parameters" +In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. - `destinationDomain` ++"uint32"++ - - The target blockchain network where the message is to be sent. +This feature is handy for recovering an incomplete transfer or when debugging. + +Here’s how you can complete a partial transfer using just the source chain and transaction hash: + +```typescript +wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); - --- + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); +``` - `recipient` ++"bytes32"++ - - The recipient's address on the destination domain. +You will need to provide the below requirements to complete the partial transfer: - --- +- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated +- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup - `messageBody` ++"bytes"++ - - The raw bytes content of the message. +This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. - ??? interface "Returns" +You can find the full code for the manual USDC transfer script below: - `nonce` ++"uint64"++ - - Nonce unique to this message. +??? code "`partial-transfer.ts`" + ```typescript + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; - ??? interface "Emits" +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); - `MessageSent` - event emitted when a new message is dispatched + // Grab chain Contexts -- these hold a reference to a cached rpc client + const rcvChain = wh.getChain('Sepolia'); -??? child "Event arguments" + // Get signer from local key + const destination = await getSigner(rcvChain); - `message` ++"bytes"++ - - The raw bytes of the message. + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) -- **`sendMessageWithCaller`** — sends a message to the destination domain and recipient, requiring a specific caller to trigger the message on the target chain. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event + // Rebuild the transfer from the source txid + const xfer = await CircleTransfer.from( + wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); - ??? interface "Parameters" + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); - `destinationDomain` ++"uint32"++ - - The target blockchain network where the message is to be sent. + console.log('Circle Transfer status: ', xfer); - --- + process.exit(0); +})(); + ``` - `recipient` ++"bytes32"++ - - The recipient's address on the destination domain. +## Automatic Transfers - --- +The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. - `destinationCaller` ++"bytes32"++ - - The caller on the destination domain. +### Set Up the Transfer Environment - --- +#### Configure Transfer Details - `messageBody` ++"bytes"++ - - The raw bytes content of the message. +The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you - ??? interface "Returns" +```typescript - `nonce` ++"uint64"++ - - Nonce unique to this message. +``` - ??? interface "Emits" +#### Initiate the Transfer - `MessageSent` - event emitted when a new message is dispatched +The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain -??? child "Event arguments" +```typescript +amt, + source.address, + destination.address, + automatic + ); +``` - `message` ++"bytes"++ - - The raw bytes of the message. +#### Log Transfer Details -- **`replaceMessage`** — replaces an original message with a new message body and/or updates the destination caller. The replacement message reuses the `_nonce` created by the original message +After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer - ??? interface "Parameters" +```typescript +console.log(`Started Transfer: `, srcTxids); - `originalMessage` ++"bytes"++ - - The original message to be replaced. + process.exit(0); +``` - --- +You can find the full code for the automatic USDC transfer script below: - `originalAttestation` ++"bytes"++ - - Attestation verifying the original message. +??? code "`automatic-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; - --- +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); - `newMessageBody` ++"bytes"++ - - The new content for the replaced message. + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); - --- + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - `newDestinationCaller` ++"bytes32"++ - - The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid. + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000_001n; - ??? interface "Returns" + const automatic = true; - None. + // Create the Circle transfer object (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); - ??? interface "Emits" + console.log('Circle Transfer object created:', xfer); - `MessageSent` - event emitted when a new message is dispatched + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); -??? child "Event arguments" + process.exit(0); +})(); + ``` - `message` ++"bytes"++ - - The raw bytes of the message. +### Run Automatic Transfer -### Token Minter Contract +Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: -The Token Minter contract manages the minting and burning of tokens across different blockchain domains. It maintains a registry that links local tokens to their corresponding remote tokens, ensuring that tokens maintain a 1:1 exchange rate across domains. +```bash +npx ts-node src/automatic-transfer.ts +``` -The contract restricts minting and burning functions to a designated Token Messenger, which ensures secure and reliable cross-chain operations. When tokens are burned on a remote domain, an equivalent amount is minted on the local domain for a specified recipient, and vice versa. +The automatic relayer will take care of fetching the attestation and completing the transfer for you. -To enhance control and flexibility, the contract includes mechanisms to pause operations, set burn limits, and update the Token Controller, which governs token minting permissions. Additionally, it provides functionality to add or remove the local Token Messenger and retrieve the local token address associated with a remote token. +## Resources -??? code "Token Minter contract" - ```solidity - /* - * Copyright (c) 2022, Circle Internet Financial Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -pragma solidity 0.7.6; +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. -import "./interfaces/ITokenMinter.sol"; -import "./interfaces/IMintBurnToken.sol"; -import "./roles/Pausable.sol"; -import "./roles/Rescuable.sol"; -import "./roles/TokenController.sol"; -import "./TokenMessenger.sol"; +## Conclusion -/** - * @title TokenMinter - * @notice Token Minter and Burner - * @dev Maintains registry of local mintable tokens and corresponding tokens on remote domains. - * This registry can be used by caller to determine which token on local domain to mint for a - * burned token on a remote domain, and vice versa. - * It is assumed that local and remote tokens are fungible at a constant 1:1 exchange rate. - */ -contract TokenMinter is ITokenMinter, TokenController, Pausable, Rescuable { - // ============ Events ============ - /** - * @notice Emitted when a local TokenMessenger is added - * @param localTokenMessenger address of local TokenMessenger - * @notice Emitted when a local TokenMessenger is added - */ - event LocalTokenMessengerAdded(address localTokenMessenger); +In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. - /** - * @notice Emitted when a local TokenMessenger is removed - * @param localTokenMessenger address of local TokenMessenger - * @notice Emitted when a local TokenMessenger is removed - */ - event LocalTokenMessengerRemoved(address localTokenMessenger); +By following these steps, you've learned how to: - // ============ State Variables ============ - // Local TokenMessenger with permission to call mint and burn on this TokenMinter - address public localTokenMessenger; +- Set up cross-chain transfers for native USDC between supported chains +- Handle both manual and automatic relaying of transactions +- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer +--- END CONTENT --- - // ============ Modifiers ============ - /** - * @notice Only accept messages from the registered message transmitter on local domain - */ - modifier onlyLocalTokenMessenger() { - require(_isLocalTokenMessenger(), "Caller not local TokenMessenger"); - _; - } +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ +--- BEGIN CONTENT --- +--- +title: Routes +description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +categories: Connect, Transfer +--- - // ============ Constructor ============ - /** - * @param _tokenController Token controller address - */ - constructor(address _tokenController) { - _setTokenController(_tokenController); - } +## Routes Overview {: #routes-overview} + +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. - // ============ External Functions ============ - /** - * @notice Mints `amount` of local tokens corresponding to the - * given (`sourceDomain`, `burnToken`) pair, to `to` address. - * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not - * map to a nonzero local token address. This mapping can be queried using - * getLocalToken(). - * @param sourceDomain Source domain where `burnToken` was burned. - * @param burnToken Burned token address as bytes32. - * @param to Address to receive minted tokens, corresponding to `burnToken`, - * on this domain. - * @param amount Amount of tokens to mint. Must be less than or equal - * to the minterAllowance of this TokenMinter for given `_mintToken`. - * @return mintToken token minted. - */ - function mint( - uint32 sourceDomain, - bytes32 burnToken, - address to, - uint256 amount - ) - external - override - whenNotPaused - onlyLocalTokenMessenger - returns (address mintToken) - { - address _mintToken = _getLocalToken(sourceDomain, burnToken); - require(_mintToken != address(0), "Mint token not supported"); - IMintBurnToken _token = IMintBurnToken(_mintToken); +Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. - require(_token.mint(to, amount), "Mint operation failed"); - return _mintToken; - } +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. - /** - * @notice Burn tokens owned by this TokenMinter. - * @param burnToken burnable token address. - * @param burnAmount amount of tokens to burn. Must be - * > 0, and <= maximum burn amount per message. - */ - function burn(address burnToken, uint256 burnAmount) - external - override - whenNotPaused - onlyLocalTokenMessenger - onlyWithinBurnLimit(burnToken, burnAmount) - { - IMintBurnToken _token = IMintBurnToken(burnToken); - _token.burn(burnAmount); - } +## Token Bridge Routes {: #token-bridge-routes} - /** - * @notice Add TokenMessenger for the local domain. Only this TokenMessenger - * has permission to call mint() and burn() on this TokenMinter. - * @dev Reverts if a TokenMessenger is already set for the local domain. - * @param newLocalTokenMessenger The address of the new TokenMessenger on the local domain. - */ - function addLocalTokenMessenger(address newLocalTokenMessenger) - external - onlyOwner - { - require( - newLocalTokenMessenger != address(0), - "Invalid TokenMessenger address" - ); +The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. - require( - localTokenMessenger == address(0), - "Local TokenMessenger already set" - ); +#### Manual Route {: #manual-route} - localTokenMessenger = newLocalTokenMessenger; +The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. - emit LocalTokenMessengerAdded(localTokenMessenger); - } +#### Automatic Route {: #automatic-route} - /** - * @notice Remove the TokenMessenger for the local domain. - * @dev Reverts if the TokenMessenger of the local domain is not set. - */ - function removeLocalTokenMessenger() external onlyOwner { - address _localTokenMessengerBeforeRemoval = localTokenMessenger; - require( - _localTokenMessengerBeforeRemoval != address(0), - "No local TokenMessenger is set" - ); +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. - delete localTokenMessenger; - emit LocalTokenMessengerRemoved(_localTokenMessengerBeforeRemoval); - } +## CCTP Routes (USDC) {: #cctp-routes-usdc} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. - /** - * @notice Set tokenController to `newTokenController`, and - * emit `SetTokenController` event. - * @dev newTokenController must be nonzero. - * @param newTokenController address of new token controller - */ - function setTokenController(address newTokenController) - external - override - onlyOwner - { - _setTokenController(newTokenController); - } +Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. - /** - * @notice Get the local token address associated with the given - * remote domain and token. - * @param remoteDomain Remote domain - * @param remoteToken Remote token - * @return local token address - */ - function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) - external - view - override - returns (address) - { - return _getLocalToken(remoteDomain, remoteToken); - } +#### Manual Route {: #manual-route-cctp} - // ============ Internal Utils ============ - /** - * @notice Returns true if the message sender is the registered local TokenMessenger - * @return True if the message sender is the registered local TokenMessenger - */ - function _isLocalTokenMessenger() internal view returns (bool) { - return - address(localTokenMessenger) != address(0) && - msg.sender == address(localTokenMessenger); - } -} - ``` +This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. - This contract and the interfaces and contracts it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMinter.sol){target=\_blank} on GitHub. +#### Automatic Route {: #automatic-route-cctp} -Most of the methods of the Token Minter contract can be called only by the registered Token Messenger. However, there is one publicly accessible method, a public view function that allows anyone to query the local token associated with a remote domain and token. +Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. -- **`getLocalToken`** — a read-only function that returns the local token address associated with a given remote domain and token +## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} - ??? interface "Parameters" +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. - `remoteDomain` ++"uint32"++ - - The remote blockchain domain where the token resides. +#### Manual Route {: #manual-route-ntt} - --- +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. - `remoteToken` ++"bytes32"++ - - The address of the token on the remote domain. +#### Automatic Route {: #automatic-route-ntt} - ??? interface "Returns" +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. - ++"address"++ - - The local token address. +## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} -## How to Interact with CCTP Contracts +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole CCTP contracts. The primary functionality revolves around the following: +#### Automatic Route {: #automatic-route-eth} -- **Sending tokens with a message payload** - initiating a cross-chain transfer of Circle-supported assets along with a message payload to a specific target address on the target chain -- **Receiving tokens with a message payload** - validating messages received from other chains via Wormhole and then minting the tokens for the recipient +Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. -### Sending Tokens and Messages +## USDT Bridge Route {: #usdt-bridge-route} -To initiate a cross-chain transfer, you must call the `transferTokensWithPayload` method of Wormhole's Circle Integration (CCTP) contract. Once you have initiated a transfer, you must fetch the attested Wormhole message and parse the transaction logs to locate a transfer message emitted by the Circle Bridge contract. Then, a request must be sent to Circle's off-chain process with the transfer message to grab the attestation from the process's response, which validates the token mint on the target chain. +Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. -To streamline this process, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank}, which exposes the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank}, including the [`CCTPSender` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. By inheriting this contract, you can transfer USDC while automatically relaying the message payload to the destination chain via a Wormhole-deployed relayer. +#### Automatic Route {: #automatic-route-usdt} -??? code "CCTP Sender contract" +Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. - ```solidity - abstract contract CCTPSender is CCTPBase { - uint8 internal constant CONSISTENCY_LEVEL_FINALIZED = 15; +## tBTC Route {: #tbtc-route} - using CCTPMessageLib for *; +You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). - mapping(uint16 => uint32) public chainIdToCCTPDomain; +Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. - /** - * Sets the CCTP Domain corresponding to chain 'chain' to be 'cctpDomain' - * So that transfers of USDC to chain 'chain' use the target CCTP domain 'cctpDomain' - * - * This action can only be performed by 'cctpConfigurationOwner', who is set to be the deployer - * - * Currently, cctp domains are: - * Ethereum: Wormhole chain id 2, cctp domain 0 - * Avalanche: Wormhole chain id 6, cctp domain 1 - * Optimism: Wormhole chain id 24, cctp domain 2 - * Arbitrum: Wormhole chain id 23, cctp domain 3 - * Base: Wormhole chain id 30, cctp domain 6 - * - * These can be set via: - * setCCTPDomain(2, 0); - * setCCTPDomain(6, 1); - * setCCTPDomain(24, 2); - * setCCTPDomain(23, 3); - * setCCTPDomain(30, 6); - */ - function setCCTPDomain(uint16 chain, uint32 cctpDomain) public { - require( - msg.sender == cctpConfigurationOwner, - "Not allowed to set CCTP Domain" - ); - chainIdToCCTPDomain[chain] = cctpDomain; - } +#### Manual Route {: #manual-route-tbtc} - function getCCTPDomain(uint16 chain) internal view returns (uint32) { - return chainIdToCCTPDomain[chain]; - } +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. +--- END CONTENT --- - /** - * transferUSDC wraps common boilerplate for sending tokens to another chain using IWormholeRelayer - * - approves the Circle TokenMessenger contract to spend 'amount' of USDC - * - calls Circle's 'depositForBurnWithCaller' - * - returns key for inclusion in WormholeRelayer `additionalVaas` argument - * - * Note: this requires that only the targetAddress can redeem transfers. - * - */ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/configuration-v0/ +--- BEGIN CONTENT --- +--- +title: Configure Your Connect Widget v0 +description: Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. +--- - function transferUSDC( - uint256 amount, - uint16 targetChain, - address targetAddress - ) internal returns (MessageKey memory) { - IERC20(USDC).approve(address(circleTokenMessenger), amount); - bytes32 targetAddressBytes32 = addressToBytes32CCTP(targetAddress); - uint64 nonce = circleTokenMessenger.depositForBurnWithCaller( - amount, - getCCTPDomain(targetChain), - targetAddressBytes32, - USDC, - targetAddressBytes32 - ); - return - MessageKey( - CCTPMessageLib.CCTP_KEY_TYPE, - abi.encodePacked(getCCTPDomain(wormhole.chainId()), nonce) - ); - } +# Configure Your Connect Widget + +## Introduction {: #introduction } + +Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. - // Publishes a CCTP transfer of 'amount' of USDC - // and requests a delivery of the transfer along with 'payload' to 'targetAddress' on 'targetChain' - // - // The second step is done by publishing a wormhole message representing a request - // to call 'receiveWormholeMessages' on the address 'targetAddress' on chain 'targetChain' - // with the payload 'abi.encode(amount, payload)' - // (and we encode the amount so it can be checked on the target chain) - function sendUSDCWithPayloadToEvm( - uint16 targetChain, - address targetAddress, - bytes memory payload, - uint256 receiverValue, - uint256 gasLimit, - uint256 amount - ) internal returns (uint64 sequence) { - MessageKey[] memory messageKeys = new MessageKey[](1); - messageKeys[0] = transferUSDC(amount, targetChain, targetAddress); +This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. - bytes memory userPayload = abi.encode(amount, payload); - address defaultDeliveryProvider = wormholeRelayer - .getDefaultDeliveryProvider(); +!!! note + For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/products/connect/configuration/data/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. - (uint256 cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - receiverValue, - gasLimit - ); +## Get Started - sequence = wormholeRelayer.sendToEvm{value: cost}( - targetChain, - targetAddress, - userPayload, - receiverValue, - 0, - gasLimit, - targetChain, - address(0x0), - defaultDeliveryProvider, - messageKeys, - CONSISTENCY_LEVEL_FINALIZED - ); - } +Configure the Wormhole Connect React component by passing a `WormholeConnectConfig` object as the `config` attribute. If using the hosted version, provide `config` and `theme` as JSON-serialized strings on the mount point. - function addressToBytes32CCTP(address addr) private pure returns (bytes32) { - return bytes32(uint256(uint160(addr))); - } +=== "React" + + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + networks: ['ethereum', 'polygon', 'solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + ethereum: 'https://rpc.ankr.com/eth', + solana: 'https://rpc.ankr.com/solana', + } } + + ``` -The `CCTPSender` abstract contract exposes the `sendUSDCWithPayloadToEvm` function. This function publishes a CCTP transfer of the provided `amount` of USDC and requests that the transfer be delivered along with a `payload` to the specified `targetAddress` on the `targetChain`. +=== "HTML Tags" -```solidity -function sendUSDCWithPayloadToEvm( - uint16 targetChain, - address targetAddress, - bytes memory payload, - uint256 receiverValue, - uint256 gasLimit, - uint256 amount -) internal returns (uint64 sequence) -``` + ```html +
+ ``` -??? interface "Parameters" +## Examples {: #examples } - `targetChain` ++"uint16"++ +Below are some examples of different ways you can configure Connect. See `WormholeConnectConfig` in the below file for a full view of the supported configuration parameters. - The target chain for the transfer. +??? code "View `WormholeConnectConfig`" + ```ts + import { + ChainName, + WormholeContext, + WormholeConfig, + ChainResourceMap, +} from 'sdklegacy'; +import MAINNET from './mainnet'; +import TESTNET from './testnet'; +import DEVNET from './devnet'; +import type { WormholeConnectConfig } from './types'; +import { + Network, + InternalConfig, + Route, + WrappedTokenAddressCache, +} from './types'; +import { + mergeCustomTokensConfig, + mergeNttGroups, + validateDefaults, +} from './utils'; +import { wrapEventHandler } from './events'; - --- +import { SDKConverter } from './converter'; - `targetAddress` ++"address"++ +import { + wormhole as getWormholeV2, + Wormhole as WormholeV2, + Network as NetworkV2, + Token as TokenV2, + Chain as ChainV2, + ChainTokens as ChainTokensV2, + WormholeConfigOverrides as WormholeConfigOverridesV2, +} from '@wormhole-foundation/sdk'; - The target address for the transfer. +import '@wormhole-foundation/sdk/addresses'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import sui from '@wormhole-foundation/sdk/sui'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import algorand from '@wormhole-foundation/sdk/algorand'; - --- +export function buildConfig( + customConfig?: WormholeConnectConfig +): InternalConfig { + const network = ( + customConfig?.network || + customConfig?.env || // TODO remove; deprecated + import.meta.env.REACT_APP_CONNECT_ENV?.toLowerCase() || + 'mainnet' + ).toLowerCase() as Network; - `payload` ++"bytes"++ + if (!['mainnet', 'testnet', 'devnet'].includes(network)) + throw new Error(`Invalid env "${network}"`); - Arbitrary payload to be delivered to the target chain via Wormhole. + const networkData = { MAINNET, DEVNET, TESTNET }[network.toUpperCase()]!; - --- + const tokens = mergeCustomTokensConfig( + networkData.tokens, + customConfig?.tokensConfig + ); - `gasLimit` ++"uint256"++ + const sdkConfig = WormholeContext.getConfig(network); - The gas limit with which to call `targetAddress`. + const rpcs = Object.assign( + {}, + sdkConfig.rpcs, + networkData.rpcs, + customConfig?.rpcs + ); - --- + const wh = getWormholeContext(network, sdkConfig, rpcs); - `amount` ++"uint256"++ + if (customConfig?.bridgeDefaults) { + validateDefaults(customConfig.bridgeDefaults, networkData.chains, tokens); + } - The amount of USDC to transfer. + const sdkConverter = new SDKConverter(wh); - --- + return { + wh, + sdkConfig, + sdkConverter, -??? interface "Returns" + v2Network: sdkConverter.toNetworkV2(network), - `sequence` ++"uint64"++ + network, + isMainnet: network === 'mainnet', + // External resources + rpcs, + rest: Object.assign( + {}, + sdkConfig.rest, + networkData.rest, + customConfig?.rest + ), + graphql: Object.assign({}, networkData.graphql, customConfig?.graphql), + wormholeApi: { + mainnet: 'https://api.wormholescan.io/', + testnet: 'https://api.testnet.wormholescan.io/', + devnet: '', + }[network], + wormholeRpcHosts: { + mainnet: [ + 'https://wormhole-v2-mainnet-api.mcf.rocks', + 'https://wormhole-v2-mainnet-api.chainlayer.network', + 'https://wormhole-v2-mainnet-api.staking.fund', + ], + testnet: [ + 'https://guardian.testnet.xlabs.xyz', + 'https://guardian-01.testnet.xlabs.xyz', + 'https://guardian-02.testnet.xlabs.xyz', + ], + devnet: ['http://localhost:7071'], + }[network], + coinGeckoApiKey: customConfig?.coinGeckoApiKey, + + // Callbacks + triggerEvent: wrapEventHandler(customConfig?.eventHandler), + validateTransfer: customConfig?.validateTransferHandler, + + // White lists + chains: networkData.chains, + chainsArr: Object.values(networkData.chains).filter((chain) => { + return customConfig?.networks + ? customConfig.networks!.includes(chain.key) + : true; + }), + tokens, + tokensArr: Object.values(tokens).filter((token) => { + return customConfig?.tokens + ? customConfig.tokens!.includes(token.key) + : true; + }), + + // For token bridge ^_^ + wrappedTokenAddressCache: new WrappedTokenAddressCache( + tokens, + sdkConverter + ), + + gasEstimates: networkData.gasEstimates, + // TODO: routes that aren't supported yet are disabled + routes: (customConfig?.routes ?? Object.values(Route)).filter((r) => + [ + Route.Bridge, + Route.Relay, + Route.NttManual, + Route.NttRelay, + Route.CCTPManual, + Route.CCTPRelay, + ].includes(r as Route) + ), + + // UI details + cta: customConfig?.cta, + explorer: customConfig?.explorer, + attestUrl: { + mainnet: 'https://portalbridge.com/advanced-tools/#/register', + devnet: '', + testnet: + 'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register', + }[network], + bridgeDefaults: customConfig?.bridgeDefaults, + cctpWarning: customConfig?.cctpWarning?.href || '', + pageHeader: customConfig?.pageHeader, + pageSubHeader: customConfig?.pageSubHeader, + menu: customConfig?.menu ?? [], + searchTx: customConfig?.searchTx, + moreTokens: customConfig?.moreTokens, + moreNetworks: customConfig?.moreNetworks, + partnerLogo: customConfig?.partnerLogo, + walletConnectProjectId: + customConfig?.walletConnectProjectId ?? + import.meta.env.REACT_APP_WALLET_CONNECT_PROJECT_ID, + showHamburgerMenu: customConfig?.showHamburgerMenu ?? false, + previewMode: !!customConfig?.previewMode, - Sequence number of the published VAA containing the delivery instructions. + // Route options + ethBridgeMaxAmount: customConfig?.ethBridgeMaxAmount ?? 5, + wstETHBridgeMaxAmount: customConfig?.wstETHBridgeMaxAmount ?? 5, -When the `sendUSDCWithPayloadToEvm` function is called, the following series of actions are executed: + // NTT config + nttGroups: mergeNttGroups( + tokens, + networkData.nttGroups, + customConfig?.nttGroups + ), -1. **USDC transfer initiation**: + // Guardian set + guardianSet: networkData.guardianSet, - - The Circle Token Messenger contract is approved to spend the specified amount of USDC. - - The `depositForBurnWithCaller` function of the Token Messenger contract is invoked - - A key is returned, which is to be provided to the Wormhole relayer for message delivery + // Render redesign views + useRedesign: customConfig?.useRedesign, + }; +} -2. **Message encoding** - the message `payload` is encoded for transmission via the Wormhole relayer. The encoded value also includes the `amount` so that it can be checked on the target chain -3. **Retrieving delivery provider** - the current default delivery provider's address is retrieved -4. **Cost calculation** - the transfer cost is calculated using the Wormhole relayer's `quoteEVMDeliveryPrice` function -5. **Message dispatch**: +// Running buildConfig with no argument generates the default configuration +const config = buildConfig(); +export default config; - - The `sendToEvm` function of the Wormhole relayer is called with the encoded payload, the delivery provider's address, and the arguments passed to `sendUSDCWithPayloadToEvm` - - The function must be called with `msg.value` set to the previously calculated cost (from step 4) - - This function publishes an instruction for the delivery provider to relay the payload and VAAs specified by the key (from step 1) to the target address on the target chain +// TODO SDKV2: REMOVE +export function getWormholeContext( + network: Network, + sdkConfig: WormholeConfig, + rpcs: ChainResourceMap +): WormholeContext { + const wh: WormholeContext = new WormholeContext(network, { + ...sdkConfig, + ...{ rpcs }, + }); -A simple example implementation is as follows: + return wh; +} -```solidity -function sendCrossChainDeposit( - uint16 targetChain, - address targetAddress, - address recipient, - uint256 amount, - uint256, - gasLimit -) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must be quoteCrossChainDeposit(targetChain)" - ); +export function getDefaultWormholeContext(network: Network): WormholeContext { + const sdkConfig = WormholeContext.getConfig(network); + const networkData = { mainnet: MAINNET, devnet: DEVNET, testnet: TESTNET }[ + network + ]!; - IERC20(USDC).transferFrom(msg.sender, address(this), amount); + const rpcs = Object.assign({}, sdkConfig.rpcs, networkData.rpcs); - bytes memory payload = abi.encode(recipient); - sendUSDCWithPayloadToEvm( - targetChain, - targetAddress, // address (on targetChain) to send token and payload to - payload, - 0, // receiver value - gasLimit, - amount - ); + return getWormholeContext(network, sdkConfig, rpcs); } -``` -The above example sends a specified amount of USDC and the recipient's address as a payload to a target contract on another chain, ensuring that the correct cost is provided for the cross-chain transfer. +export async function getWormholeContextV2(): Promise> { + if (config.v2Wormhole) return config.v2Wormhole; + config.v2Wormhole = await newWormholeContextV2(); + return config.v2Wormhole; +} -### Receiving Tokens and Messages +export async function newWormholeContextV2(): Promise> { + const v2Config: WormholeConfigOverridesV2 = { chains: {} }; -To complete the cross-chain transfer, you must invoke the `redeemTokensWithPayload` function on the target Wormhole Circle Integration contract. This function verifies the message's authenticity, decodes the payload, confirms the recipient and sender, checks message delivery, and then calls the `receiveMessage` function of the [Message Transmitter](#message-transmitter-contract) contract. + for (const key in config.chains) { + const chainV1 = key as ChainName; + const chainConfigV1 = config.chains[chainV1]!; -Using the Wormhole-deployed relayer automatically triggers the `receiveWormholeMessages` function. This function is defined in the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} from the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank} and is implemented within the [`CCTPReceiver` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. + const chainContextV1 = chainConfigV1.context; -??? code "CCTP Receiver contract" + const chainV2 = config.sdkConverter.toChainV2( + chainV1 as ChainName + ) as ChainV2; - ```solidity - abstract contract CCTPReceiver is CCTPBase { - function redeemUSDC( - bytes memory cctpMessage - ) internal returns (uint256 amount) { - (bytes memory message, bytes memory signature) = abi.decode( - cctpMessage, - (bytes, bytes) - ); - uint256 beforeBalance = IERC20(USDC).balanceOf(address(this)); - circleMessageTransmitter.receiveMessage(message, signature); - return IERC20(USDC).balanceOf(address(this)) - beforeBalance; - } + const rpc = config.rpcs[chainV1]; + const tokenMap: ChainTokensV2 = {}; - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable { - // Currently, 'sendUSDCWithPayloadToEVM' only sends one CCTP transfer - // That can be modified if the integrator desires to send multiple CCTP transfers - // in which case the following code would have to be modified to support - // redeeming these multiple transfers and checking that their 'amount's are accurate - require( - additionalMessages.length <= 1, - "CCTP: At most one Message is supported" - ); + for (const token of config.tokensArr) { + const nativeChainV2 = config.sdkConverter.toChainV2(token.nativeChain); - uint256 amountUSDCReceived; - if (additionalMessages.length == 1) - amountUSDCReceived = redeemUSDC(additionalMessages[0]); + const tokenV2: Partial = { + key: token.key, + chain: chainV2, + symbol: token.symbol, + }; - (uint256 amount, bytes memory userPayload) = abi.decode( - payload, - (uint256, bytes) - ); + if (nativeChainV2 == chainV2) { + const decimals = + token.decimals[chainContextV1] ?? token.decimals.default; + if (!decimals) { + continue; + } else { + tokenV2.decimals = decimals; + } + const address = config.sdkConverter.getNativeTokenAddressV2(token); + if (!address) throw new Error('Token must have address'); + tokenV2.address = address; + } else { + tokenV2.original = nativeChainV2; + if (token.foreignAssets) { + const fa = token.foreignAssets[chainV1]!; - // Check that the correct amount was received - // It is important to verify that the 'USDC' sent in by the relayer is the same amount - // that the sender sent in on the source chain - require(amount == amountUSDCReceived, "Wrong amount received"); + if (!fa) { + continue; + } else { + tokenV2.address = fa.address; + tokenV2.decimals = fa.decimals; + } + } else { + continue; + } + } - receivePayloadAndUSDC( - userPayload, - amountUSDCReceived, - sourceAddress, - sourceChain, - deliveryHash - ); + tokenMap[token.key] = tokenV2 as TokenV2; } - // Implement this function to handle in-bound deliveries that include a CCTP transfer - function receivePayloadAndUSDC( - bytes memory payload, - uint256 amountUSDCReceived, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) internal virtual {} -} - ``` - -Although you do not need to interact with the `receiveWormholeMessages` function directly, it's important to understand what it does. This function processes cross-chain messages and USDC transfers via Wormhole's Circle (CCTP) Bridge. Here's a summary of what it does: - -1. **Validate additional messages** - the function checks that there is at most one CCTP transfer message in the `additionalMessages` array, as it currently only supports processing a single CCTP transfer -2. **Redeem USDC**: - - If there is a CCTP message, it calls the `redeemUSDC` function of the `CCTPReceiver` contract to decode and redeem the USDC - - This results in the call of the `receiveMessage` function of Circle's Message Transmitter contract to redeem the USDC based on the provided message and signature - - The amount of USDC received is calculated by subtracting the contract's previous balance from the current balance after redeeming the USDC -3. **Decode payload** - the incoming payload is decoded, extracting both the expected amount of USDC and a `userPayload` (which could be any additional data) -4. **Verify the amount** - it ensures that the amount of USDC received matches the amount encoded in the payload. If the amounts don't match, the transaction is reverted -5. **Handle the payload and USDC** - after verifying the amounts, `receivePayloadAndUSDC` is called, which is meant to handle the actual logic for processing the received payload and USDC transfer - -You'll need to implement the `receivePayloadAndUSDC` function to transfer the USDC and handle the payload as your application needs. A simple example implementation is as follows: - -```solidity -function receivePayloadAndUSDC( - bytes memory payload, - uint256 amountUSDCReceived, - bytes32, // sourceAddress - uint16, // sourceChain - bytes32 // deliveryHash -) internal override onlyWormholeRelayer { - address recipient = abi.decode(payload, (address)); + v2Config.chains![chainV2] = { rpc, tokenMap }; + } - IERC20(USDC).transfer(recipient, amountUSDCReceived); + return await getWormholeV2( + config.v2Network, + [evm, solana, aptos, cosmwasm, sui, algorand], + v2Config + ); } -``` -## Complete Example - -To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/configuration/configuration-v0/ ---- BEGIN CONTENT --- ---- -title: Configure Your Connect Widget v0 -description: Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. ---- - -# Configure Your Connect Widget - -## Introduction {: #introduction } - -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. +// setConfig can be called afterwards to override the default config with integrator-provided config +export function setConfig(customConfig?: WormholeConnectConfig) { + const newConfig: InternalConfig = buildConfig(customConfig); -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. + // We overwrite keys in the existing object so the references to the config + // imported elsewhere point to the new values + for (const key in newConfig) { + /* @ts-ignore */ + config[key] = newConfig[key]; + } +} -!!! note - For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/build/transfers/connect/configuration/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. +// TODO: add config validation step to buildConfig +//validateConfigs(); + + ``` -## Get Started +### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints } -Configure the Wormhole Connect React component by passing a `WormholeConnectConfig` object as the `config` attribute. If using the hosted version, provide `config` and `theme` as JSON-serialized strings on the mount point. +Specify supported networks, tokens, and custom RPC endpoints. Your users may encounter rate limits using public RPC endpoints if you don't provide your own. -=== "React" +=== "Mainnet" - ```ts + ```js import WormholeConnect, { WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; - + const config: WormholeConnectConfig = { + env: 'mainnet', networks: ['ethereum', 'polygon', 'solana'], tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], rpcs: { ethereum: 'https://rpc.ankr.com/eth', solana: 'https://rpc.ankr.com/solana', - } + }, +}; + +function App() { + return ; } - - ``` -=== "HTML Tags" +=== "Testnet" - ```html -
+ ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + env: 'testnet', + networks: ['sepolia', 'arbitrum_sepolia', 'base_sepolia', 'fuji'], + + rpcs: { + fuji: 'https://rpc.ankr.com/avalanche_fuji', + base_sepolia: 'https://base-sepolia-rpc.publicnode.com', + }, +}; + +function App() { + return ; +} ``` -## Examples {: #examples } +!!! note + For a complete list of testnet chain names that can be manually added, see the [Testnet Chains List](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/tokenRegistry/src/scripts/importConnect.ts#L44-L55){target=\_blank}. -Below are some examples of different ways you can configure Connect. See `WormholeConnectConfig` in the below file for a full view of the supported configuration parameters. +### Fully Customized Theme {: #fully-customized-theme } + +Wormhole Connect offers a high level of customizability that suits and integrates with your application's design, including various options for buttons, backgrounds, popovers, fonts, and more. The following example demonstrates a variety of appearance customizations. Remember, if you prefer a visual to aid in designing your widget, you can use the [no code style interface](https://connect-in-style.wormhole.com/){target=\_blank}. + +```jsx +import WormholeConnect, { + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; +import red from '@mui/material/colors/red'; +import lightblue from '@mui/material/colors/lightBlue'; +import grey from '@mui/material/colors/grey'; +import green from '@mui/material/colors/green'; +import orange from '@mui/material/colors/orange'; + +const customTheme: WormholeConnectTheme = { + mode: 'dark', + primary: grey, + secondary: grey, + divider: 'rgba(255, 255, 255, 0.2)', + background: { + default: '#232323', + }, + text: { + primary: '#ffffff', + secondary: grey[500], + }, + error: red, + info: lightblue, + success: green, + warning: orange, + button: { + primary: 'rgba(255, 255, 255, 0.2)', + primaryText: '#ffffff', + disabled: 'rgba(255, 255, 255, 0.1)', + disabledText: 'rgba(255, 255, 255, 0.4)', + action: orange[300], + actionText: '#000000', + hover: 'rgba(255, 255, 255, 0.7)', + }, + options: { + hover: '#474747', + select: '#5b5b5b', + }, + card: { + background: '#333333', + secondary: '#474747', + elevation: 'none', + }, + popover: { + background: '#1b2033', + secondary: 'rgba(255, 255, 255, 0.5)', + elevation: 'none', + }, + modal: { + background: '#474747', + }, + font: { + primary: 'Impact', + header: 'Impact', + }, +}; + +export default function App() { + return ; +} +``` + +### Environment {: #environment } + +You can configure Connect to be used in Testnet environments, too. You can toggle between Mainnet and Testnet environments by defining the `WormholeConnectConfig` as follows: + +=== "Mainnet" -??? code "View `WormholeConnectConfig`" ```ts - import { - ChainName, - WormholeContext, - WormholeConfig, - ChainResourceMap, -} from 'sdklegacy'; -import MAINNET from './mainnet'; -import TESTNET from './testnet'; -import DEVNET from './devnet'; -import type { WormholeConnectConfig } from './types'; -import { - Network, - InternalConfig, - Route, - WrappedTokenAddressCache, -} from './types'; -import { - mergeCustomTokensConfig, - mergeNttGroups, - validateDefaults, -} from './utils'; -import { wrapEventHandler } from './events'; + const config: WormholeConnectConfig = { + env: 'mainnet', + }; + ``` -import { SDKConverter } from './converter'; +=== "Testnet" -import { - wormhole as getWormholeV2, - Wormhole as WormholeV2, - Network as NetworkV2, - Token as TokenV2, - Chain as ChainV2, - ChainTokens as ChainTokensV2, - WormholeConfigOverrides as WormholeConfigOverridesV2, -} from '@wormhole-foundation/sdk'; + ```ts + const config: WormholeConnectConfig = { + env: 'testnet', + }; + ``` +### Custom RPC Endpoint {: #custom-rpc-endpoint } -import '@wormhole-foundation/sdk/addresses'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import sui from '@wormhole-foundation/sdk/sui'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import algorand from '@wormhole-foundation/sdk/algorand'; +You can define a custom RPC provider for your Connect widget to use. This can be especially helpful if you'd like to replace public endpoints with dedicated or private endpoints. -export function buildConfig( - customConfig?: WormholeConnectConfig -): InternalConfig { - const network = ( - customConfig?.network || - customConfig?.env || // TODO remove; deprecated - import.meta.env.REACT_APP_CONNECT_ENV?.toLowerCase() || - 'mainnet' - ).toLowerCase() as Network; +```ts +const config: WormholeConnectConfig = { + rpcs: { + solana: 'https://rpc.ankr.com/solana/ee827255553bb0fa9e0aaeab27e988707e60ea06ae36be0658b778072e94979e', + }, +}; +``` - if (!['mainnet', 'testnet', 'devnet'].includes(network)) - throw new Error(`Invalid env "${network}"`); +### Arbitrary Token {: #arbitrary-token } - const networkData = { MAINNET, DEVNET, TESTNET }[network.toUpperCase()]!; +The following section shows how to add an arbitrary token to your deployment of Connect. - const tokens = mergeCustomTokensConfig( - networkData.tokens, - customConfig?.tokensConfig - ); +!!! note + You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with Connect. - const sdkConfig = WormholeContext.getConfig(network); +This example configuration limits Connect to the Solana and Ethereum networks and a handful of tokens, including `BSKT`, which isn't built in by default and provided under the `tokensConfig` key. - const rpcs = Object.assign( - {}, - sdkConfig.rpcs, - networkData.rpcs, - customConfig?.rpcs - ); +See [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. + +```json +const config: WormholeConnectConfig = { + networks: ['solana', 'ethereum'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC', 'BSKT'], + tokensConfig: { + BSKT: { + key: 'BSKT', + symbol: 'BSKT', + nativeChain: 'solana', + tokenId: { + chain: 'solana', + address: '6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA', + }, + coinGeckoId: 'basket', + icon: 'https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891', + color: '#2894EE', + decimals: { + default: 5, + }, + }, + }, +}; +``` + +## More Configuration Options {: #more-configuration-options } + +### Whitelisting Tokens {: #whitelisting-tokens } + +By default, Connect will offer its complete built-in list of assets, but you can restrict the displayed assets by defining a subset of tokens under `tokens`. The default full list is as follows: + +| Mainnet | Testnet | +|:--------------:|:----------------------------------:| +| ETH | ETH, ETHsepolia | +| WETH | WETH, WETHsepolia | +| USDCeth | USDCeth | +| WBTC | - | +| USDT | - | +| DAI | - | +| BUSD | - | +| MATIC | MATIC | +| WMATIC | WMATIC | +| USDCpolygon | - | +| BNB | BNB | +| WBNB | WBNB | +| USDCbnb | - | +| AVAX | AVAX | +| WAVAX | WAVAX | +| USDCavax | USDCavax | +| FTM | FTM | +| WFTM | WFTM | +| CELO | CELO | +| GLMR | GLMR | +| WGLMR | WGLMR | +| SOL | WSOL | +| PYTH | - | +| SUI | SUI | +| USDCsol | - | +| APT | APT | +| ETHarbitrum | ETHarbitrum, ETHarbitrum_sepolia | +| WETHarbitrum | WETHarbitrum, WETHarbitrum_sepolia | +| USDCarbitrum | USDCarbitrum | +| ETHoptimism | ETHoptimism, ETHoptimism_sepolia | +| WETHoptimism | WETHoptimism, WETHoptimism_sepolia | +| USDCoptimism | USDCoptimism | +| ETHbase | ETHbase, ETHbase_sepolia | +| WETHbase | WETHbase, WETHbase_sepolia | +| tBTC | tBTC | +| tBTCpolygon | tBTCpolygon | +| tBTCoptimism | tBTCoptimism | +| tBTCarbitrum | tBTCarbitrum | +| tBTCbase | tBTCbase | +| tBTCsol | tBTCsol | +| WETHpolygon | - | +| WETHbsc | - | +| wstETH | wstETH | +| wstETHarbitrum | - | +| wstETHoptimism | - | +| wstETHpolygon | - | +| wstETHbase | - | - const wh = getWormholeContext(network, sdkConfig, rpcs); +### Routes {: #routes } - if (customConfig?.bridgeDefaults) { - validateDefaults(customConfig.bridgeDefaults, networkData.chains, tokens); - } +By default, Connect will offer its complete built-in list of routes, but you can restrict the possible route assets by defining a subset under `routes.` By default, Connect will offer its complete built-in list: - const sdkConverter = new SDKConverter(wh); +| Mainnet | Testnet | +|:------------:|:----------:| +| bridge | bridge | +| relay | relay | +| cctpManual | cctpManual | +| cctpRelay | cctpRelay | +| nttManual | nttManual | +| nttRelay | nttRelay | +| ethBridge | - | +| wstETHBridge | - | +| usdtBridge | - | +| tBTC | tBTC | - return { - wh, - sdkConfig, - sdkConverter, +### Wallet Set Up {: #wallet-connect-project-id } - v2Network: sdkConverter.toNetworkV2(network), +When using Wormhole Connect, your selected blockchain network determines the available wallet options. - network, - isMainnet: network === 'mainnet', - // External resources - rpcs, - rest: Object.assign( - {}, - sdkConfig.rest, - networkData.rest, - customConfig?.rest - ), - graphql: Object.assign({}, networkData.graphql, customConfig?.graphql), - wormholeApi: { - mainnet: 'https://api.wormholescan.io/', - testnet: 'https://api.testnet.wormholescan.io/', - devnet: '', - }[network], - wormholeRpcHosts: { - mainnet: [ - 'https://wormhole-v2-mainnet-api.mcf.rocks', - 'https://wormhole-v2-mainnet-api.chainlayer.network', - 'https://wormhole-v2-mainnet-api.staking.fund', - ], - testnet: [ - 'https://guardian.testnet.xlabs.xyz', - 'https://guardian-01.testnet.xlabs.xyz', - 'https://guardian-02.testnet.xlabs.xyz', - ], - devnet: ['http://localhost:7071'], - }[network], - coinGeckoApiKey: customConfig?.coinGeckoApiKey, + - For EVM chains, wallets like MetaMask and WalletConnect are supported + - For Solana, you'll see options such as Phantom, Torus, and Coin98 - // Callbacks - triggerEvent: wrapEventHandler(customConfig?.eventHandler), - validateTransfer: customConfig?.validateTransferHandler, +The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. - // White lists - chains: networkData.chains, - chainsArr: Object.values(networkData.chains).filter((chain) => { - return customConfig?.networks - ? customConfig.networks!.includes(chain.key) - : true; - }), - tokens, - tokensArr: Object.values(tokens).filter((token) => { - return customConfig?.tokens - ? customConfig.tokens!.includes(token.key) - : true; - }), +If you would like to offer WalletConnect as a supported wallet option, you'll need to obtain a project ID on the [WalletConnect cloud dashboard](https://cloud.walletconnect.com/){target=\_blank}. - // For token bridge ^_^ - wrappedTokenAddressCache: new WrappedTokenAddressCache( - tokens, - sdkConverter - ), +### Toggle Hamburger Menu {: #toggle-hamburger-menu } - gasEstimates: networkData.gasEstimates, - // TODO: routes that aren't supported yet are disabled - routes: (customConfig?.routes ?? Object.values(Route)).filter((r) => - [ - Route.Bridge, - Route.Relay, - Route.NttManual, - Route.NttRelay, - Route.CCTPManual, - Route.CCTPRelay, - ].includes(r as Route) - ), +By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, causing the links to be positioned at the bottom. - // UI details - cta: customConfig?.cta, - explorer: customConfig?.explorer, - attestUrl: { - mainnet: 'https://portalbridge.com/advanced-tools/#/register', - devnet: '', - testnet: - 'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register', - }[network], - bridgeDefaults: customConfig?.bridgeDefaults, - cctpWarning: customConfig?.cctpWarning?.href || '', - pageHeader: customConfig?.pageHeader, - pageSubHeader: customConfig?.pageSubHeader, - menu: customConfig?.menu ?? [], - searchTx: customConfig?.searchTx, - moreTokens: customConfig?.moreTokens, - moreNetworks: customConfig?.moreNetworks, - partnerLogo: customConfig?.partnerLogo, - walletConnectProjectId: - customConfig?.walletConnectProjectId ?? - import.meta.env.REACT_APP_WALLET_CONNECT_PROJECT_ID, - showHamburgerMenu: customConfig?.showHamburgerMenu ?? false, - previewMode: !!customConfig?.previewMode, +#### Add Extra Menu Entry {: #add-extra-menu-entry } - // Route options - ethBridgeMaxAmount: customConfig?.ethBridgeMaxAmount ?? 5, - wstETHBridgeMaxAmount: customConfig?.wstETHBridgeMaxAmount ?? 5, +By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): - // NTT config - nttGroups: mergeNttGroups( - tokens, - networkData.nttGroups, - customConfig?.nttGroups - ), +| Property | Description | +|:--------:|:-------------------------------------------:| +| `label` | Link name to show up | +| `href` | Target URL or URN | +| `target` | Anchor standard target, by default `_blank` | +| `order` | Order where the new item should be injected | - // Guardian set - guardianSet: networkData.guardianSet, +#### Sample Configuration {: #sample-configuration } - // Render redesign views - useRedesign: customConfig?.useRedesign, - }; +```json +{ + "showHamburgerMenu": false, + "menu": [ + { + "label": "Advance Tools", + "href": "https://portalbridge.com", + "target": "_self", + "order": 1 + } + ] } +``` -// Running buildConfig with no argument generates the default configuration -const config = buildConfig(); -export default config; +### CoinGecko API Key {: #coingecko-api-key } -// TODO SDKV2: REMOVE -export function getWormholeContext( - network: Network, - sdkConfig: WormholeConfig, - rpcs: ChainResourceMap -): WormholeContext { - const wh: WormholeContext = new WormholeContext(network, { - ...sdkConfig, - ...{ rpcs }, - }); +The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. - return wh; -} +### More Networks {: #more-networks } -export function getDefaultWormholeContext(network: Network): WormholeContext { - const sdkConfig = WormholeContext.getConfig(network); - const networkData = { mainnet: MAINNET, devnet: DEVNET, testnet: TESTNET }[ - network - ]!; +Specify a set of extra networks to be displayed on the network selection modal, each linking to a different page, dApp, or mobile app the user will be redirected to. The following properties are accessed through the `moreNetworks` property (e.g., `moreNetworks.href`): - const rpcs = Object.assign({}, sdkConfig.rpcs, networkData.rpcs); +|
Property
| Description | +|:--------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `href` | **Required**. Default value for missing network hrefs | +| `target` | Default value for missing network link targets. Defaults to `_self` | +| `description` | Brief description that should be displayed as a tooltip when the user hovers over a more network icon. Used as default for missing network descriptions | +| `networks[].icon` | **Required**. URL data encoded icon to display | +| `networks[].href` | Network href to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | +| `networks[].label` | **Required**. Display text | +| `networks[].name` | Unique network key. Defaults to a snake_case version of the label | +| `networks[].description` | Description value. Defaults to `moreNetworks.description` | +| `networks[].target` | href target value. Defaults to `moreNetworks.target` | +| `networks[].showOpenInNewIcon` | Disable top right open in new icon. Defaults to **true** if target is `_blank` or **false** if target is `_self` | - return getWormholeContext(network, sdkConfig, rpcs); +??? code "View full configuration" + ```json + { + ... + "moreNetworks": { + "href": "https://example.com", + "target": "_blank", + "description": "brief description that should be displayed as tooltip when the user hovers over a more network icon", + "networks": [ + { + "icon": "https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891", + "name": "more", + "label": "More networks", + "href": "https://portalbridge.com/#/transfer", + "showOpenInNewIcon": false + } + ] + } + ... } + ``` -export async function getWormholeContextV2(): Promise> { - if (config.v2Wormhole) return config.v2Wormhole; - config.v2Wormhole = await newWormholeContextV2(); - return config.v2Wormhole; -} +### More Tokens {: #more-tokens } -export async function newWormholeContextV2(): Promise> { - const v2Config: WormholeConfigOverridesV2 = { chains: {} }; +Show a particular entry on the select tokens modal, redirecting the user to a different page, dApp, or mobile app. The following properties are accessed through the `moreTokens` property (e.g., `moreTokens.label`): + +| Property | Description | +|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `label` | **Required**. Display text | +| `href` | **Required**. URL to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | +| `target` | href target. Defaults to `_self` | - for (const key in config.chains) { - const chainV1 = key as ChainName; - const chainConfigV1 = config.chains[chainV1]!; +### Explorer {: #explorer } - const chainContextV1 = chainConfigV1.context; +Enable the explorer button to allow users to search for their transactions on a given explorer, filtering by their wallet address. The following properties are accessed through the `explorer` property (e.g., `explorer.label`): - const chainV2 = config.sdkConverter.toChainV2( - chainV1 as ChainName - ) as ChainV2; +| Property | Description | +|:--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `label` | Display text. Defaults to `Transactions` | +| `href` | **Required**. URL of the explorer, for instance [https://wormholescan.io/](https://wormholescan.io/){target=\_blank}. If present, the value `address` is replaced with the connected wallet address | +| `target` | `href` target. Defaults to `_blank` | +--- END CONTENT --- - const rpc = config.rpcs[chainV1]; - const tokenMap: ChainTokensV2 = {}; +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ +--- BEGIN CONTENT --- +--- +title: Connect Data Configuration +description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +categories: Connect, Transfer +--- - for (const token of config.tokensArr) { - const nativeChainV2 = config.sdkConverter.toChainV2(token.nativeChain); +## Data Configuration - const tokenV2: Partial = { - key: token.key, - chain: chainV2, - symbol: token.symbol, - }; +This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - if (nativeChainV2 == chainV2) { - const decimals = - token.decimals[chainContextV1] ?? token.decimals.default; - if (!decimals) { - continue; - } else { - tokenV2.decimals = decimals; - } - const address = config.sdkConverter.getNativeTokenAddressV2(token); - if (!address) throw new Error('Token must have address'); - tokenV2.address = address; - } else { - tokenV2.original = nativeChainV2; - if (token.foreignAssets) { - const fa = token.foreignAssets[chainV1]!; +## Get Started - if (!fa) { - continue; - } else { - tokenV2.address = fa.address; - tokenV2.decimals = fa.decimals; - } - } else { - continue; - } - } +Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. - tokenMap[token.key] = tokenV2 as TokenV2; - } +=== "React integration" - v2Config.chains![chainV2] = { rpc, tokenMap }; - } + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - return await getWormholeV2( - config.v2Network, - [evm, solana, aptos, cosmwasm, sui, algorand], - v2Config - ); +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + } } -// setConfig can be called afterwards to override the default config with integrator-provided config -export function setConfig(customConfig?: WormholeConnectConfig) { - const newConfig: InternalConfig = buildConfig(customConfig); + + ``` - // We overwrite keys in the existing object so the references to the config - // imported elsewhere point to the new values - for (const key in newConfig) { - /* @ts-ignore */ - config[key] = newConfig[key]; - } -} +=== "Hosted integration" -// TODO: add config validation step to buildConfig -//validateConfigs(); -
+ ```ts + import WormholeConnect, { + wormholeConnectHosted, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; + +const container = document.getElementById('bridge-container'); + +wormholeConnectHosted(container, { + config, +}); ``` -### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints } +!!! note + The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. -Specify supported networks, tokens, and custom RPC endpoints. Your users may encounter rate limits using public RPC endpoints if you don't provide your own. +## Examples {: #examples } + +### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } + +Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. === "Mainnet" @@ -10890,12 +7344,10 @@ Specify supported networks, tokens, and custom RPC endpoints. Your users may enc } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - env: 'mainnet', - networks: ['ethereum', 'polygon', 'solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + chains: ['Ethereum', 'Polygon', 'Solana'], rpcs: { - ethereum: 'https://rpc.ankr.com/eth', - solana: 'https://rpc.ankr.com/solana', + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', }, }; @@ -10912,12 +7364,12 @@ function App() { } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - env: 'testnet', - networks: ['sepolia', 'arbitrum_sepolia', 'base_sepolia', 'fuji'], - + // You can use Connect with testnet chains by specifying "network": + network: 'Testnet', + chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], rpcs: { - fuji: 'https://rpc.ankr.com/avalanche_fuji', - base_sepolia: 'https://base-sepolia-rpc.publicnode.com', + Avalanche: 'https://rpc.ankr.com/avalanche_fuji', + BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', }, }; @@ -10927,938 +7379,1050 @@ function App() { ``` !!! note - For a complete list of testnet chain names that can be manually added, see the [Testnet Chains List](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/tokenRegistry/src/scripts/importConnect.ts#L44-L55){target=\_blank}. + For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. -### Fully Customized Theme {: #fully-customized-theme } +### Configuring Routes -Wormhole Connect offers a high level of customizability that suits and integrates with your application's design, including various options for buttons, backgrounds, popovers, fonts, and more. The following example demonstrates a variety of appearance customizations. Remember, if you prefer a visual to aid in designing your widget, you can use the [no code style interface](https://connect-in-style.wormhole.com/){target=\_blank}. +By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. -```jsx +#### Available Route Plugins + +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: + +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route +- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route +- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol + +In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. + +For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. + +#### Example: Offer Only CCTP Transfers + +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: + +```typescript import WormholeConnect, { - WormholeConnectTheme, + AutomaticCCTPRoute, + WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; -import red from '@mui/material/colors/red'; -import lightblue from '@mui/material/colors/lightBlue'; -import grey from '@mui/material/colors/grey'; -import green from '@mui/material/colors/green'; -import orange from '@mui/material/colors/orange'; -const customTheme: WormholeConnectTheme = { - mode: 'dark', - primary: grey, - secondary: grey, - divider: 'rgba(255, 255, 255, 0.2)', - background: { - default: '#232323', - }, - text: { - primary: '#ffffff', - secondary: grey[500], - }, - error: red, - info: lightblue, - success: green, - warning: orange, - button: { - primary: 'rgba(255, 255, 255, 0.2)', - primaryText: '#ffffff', - disabled: 'rgba(255, 255, 255, 0.1)', - disabledText: 'rgba(255, 255, 255, 0.4)', - action: orange[300], - actionText: '#000000', - hover: 'rgba(255, 255, 255, 0.7)', - }, - options: { - hover: '#474747', - select: '#5b5b5b', - }, - card: { - background: '#333333', - secondary: '#474747', - elevation: 'none', - }, - popover: { - background: '#1b2033', - secondary: 'rgba(255, 255, 255, 0.5)', - elevation: 'none', - }, - modal: { - background: '#474747', - }, - font: { - primary: 'Impact', - header: 'Impact', - }, +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], }; -export default function App() { - return ; -} +; +``` + +#### Example: Offer All Default Routes and Third-Party Plugins + +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. + +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +import { myNttConfig } from './consts'; // Custom NTT configuration + +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; + +; ``` -### Environment {: #environment } +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. -You can configure Connect to be used in Testnet environments, too. You can toggle between Mainnet and Testnet environments by defining the `WormholeConnectConfig` as follows: +### Adding Custom Tokens {: #custom-tokens } -=== "Mainnet" +The following section shows how to add an arbitrary token to your deployment of Connect. - ```ts - const config: WormholeConnectConfig = { - env: 'mainnet', - }; - ``` +!!! note + You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. -=== "Testnet" +This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. - ```ts - const config: WormholeConnectConfig = { - env: 'testnet', - }; - ``` -### Custom RPC Endpoint {: #custom-rpc-endpoint } +See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. -You can define a custom RPC provider for your Connect widget to use. This can be especially helpful if you'd like to replace public endpoints with dedicated or private endpoints. +```typescript +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -```ts const config: WormholeConnectConfig = { - rpcs: { - solana: 'https://rpc.ankr.com/solana/ee827255553bb0fa9e0aaeab27e988707e60ea06ae36be0658b778072e94979e', + tokensConfig: { + BONK: { + key: 'BONK', + symbol: 'BONK', + nativeChain: 'Ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', + }, + coinGeckoId: 'bonk', + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', + }, }, }; ``` -### Arbitrary Token {: #arbitrary-token } +### Whitelisting Tokens {: #whitelisting-tokens } -The following section shows how to add an arbitrary token to your deployment of Connect. +Connect offers a list of built-in tokens by default. You can see it below: -!!! note - You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with Connect. +- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} +- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} -This example configuration limits Connect to the Solana and Ethereum networks and a handful of tokens, including `BSKT`, which isn't built in by default and provided under the `tokensConfig` key. +You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. -See [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -```json const config: WormholeConnectConfig = { - networks: ['solana', 'ethereum'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC', 'BSKT'], + chains: ['Ethereum', 'Solana'], + tokens: ['ETH', 'SOL', 'BONK'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, tokensConfig: { - BSKT: { - key: 'BSKT', - symbol: 'BSKT', - nativeChain: 'solana', + BONK: { + key: 'BONK', + symbol: 'BONK', + icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', tokenId: { - chain: 'solana', - address: '6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA', - }, - coinGeckoId: 'basket', - icon: 'https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891', - color: '#2894EE', - decimals: { - default: 5, + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', }, + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', }, }, }; -``` -## More Configuration Options {: #more-configuration-options } +function App() { + return ; +} +``` -### Whitelisting Tokens {: #whitelisting-tokens } +You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. -By default, Connect will offer its complete built-in list of assets, but you can restrict the displayed assets by defining a subset of tokens under `tokens`. The default full list is as follows: +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -| Mainnet | Testnet | -|:--------------:|:----------------------------------:| -| ETH | ETH, ETHsepolia | -| WETH | WETH, WETHsepolia | -| USDCeth | USDCeth | -| WBTC | - | -| USDT | - | -| DAI | - | -| BUSD | - | -| MATIC | MATIC | -| WMATIC | WMATIC | -| USDCpolygon | - | -| BNB | BNB | -| WBNB | WBNB | -| USDCbnb | - | -| AVAX | AVAX | -| WAVAX | WAVAX | -| USDCavax | USDCavax | -| FTM | FTM | -| WFTM | WFTM | -| CELO | CELO | -| GLMR | GLMR | -| WGLMR | WGLMR | -| SOL | WSOL | -| PYTH | - | -| SUI | SUI | -| USDCsol | - | -| APT | APT | -| ETHarbitrum | ETHarbitrum, ETHarbitrum_sepolia | -| WETHarbitrum | WETHarbitrum, WETHarbitrum_sepolia | -| USDCarbitrum | USDCarbitrum | -| ETHoptimism | ETHoptimism, ETHoptimism_sepolia | -| WETHoptimism | WETHoptimism, WETHoptimism_sepolia | -| USDCoptimism | USDCoptimism | -| ETHbase | ETHbase, ETHbase_sepolia | -| WETHbase | WETHbase, WETHbase_sepolia | -| tBTC | tBTC | -| tBTCpolygon | tBTCpolygon | -| tBTCoptimism | tBTCoptimism | -| tBTCarbitrum | tBTCarbitrum | -| tBTCbase | tBTCbase | -| tBTCsol | tBTCsol | -| WETHpolygon | - | -| WETHbsc | - | -| wstETH | wstETH | -| wstETHarbitrum | - | -| wstETHoptimism | - | -| wstETHpolygon | - | -| wstETHbase | - | +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Solana'], + tokens: [ + // Whitelist BONK on every whitelisted chain + 'BONK', + // Also whitelist USDC, specifically on Solana + ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] + ], + ... +}; -### Routes {: #routes } +function App() { + return ; +} +``` -By default, Connect will offer its complete built-in list of routes, but you can restrict the possible route assets by defining a subset under `routes.` By default, Connect will offer its complete built-in list: +### User-Inputted Tokens {: #user-inputted-tokens } -| Mainnet | Testnet | -|:------------:|:----------:| -| bridge | bridge | -| relay | relay | -| cctpManual | cctpManual | -| cctpRelay | cctpRelay | -| nttManual | nttManual | -| nttRelay | nttRelay | -| ethBridge | - | -| wstETHBridge | - | -| usdtBridge | - | -| tBTC | tBTC | +As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). -### Wallet Set Up {: #wallet-connect-project-id } +If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: -When using Wormhole Connect, your selected blockchain network determines the available wallet options. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - - For EVM chains, wallets like MetaMask and WalletConnect are supported - - For Solana, you'll see options such as Phantom, Torus, and Coin98 +const config: WormholeConnectConfig = { + ui: { + disableUserInputtedTokens: true + } +}; -The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. +function App() { + return ; +} +``` -If you would like to offer WalletConnect as a supported wallet option, you'll need to obtain a project ID on the [WalletConnect cloud dashboard](https://cloud.walletconnect.com/){target=\_blank}. +Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. -### Toggle Hamburger Menu {: #toggle-hamburger-menu } +### Transaction Settings {: #transaction-settings } -By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, causing the links to be positioned at the bottom. +Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. -#### Add Extra Menu Entry {: #add-extra-menu-entry } +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): +const config: WormholeConnectConfig = { + transactionSettings: { + Solana: { + priorityFee: { + // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. + // For example, you can set percentile to 0.95 to make Connect compute the + // 95th percentile priority fee amount based on recent transactions + percentile: 0.95, -| Property | Description | -|:--------:|:-------------------------------------------:| -| `label` | Link name to show up | -| `href` | Target URL or URN | -| `target` | Anchor standard target, by default `_blank` | -| `order` | Order where the new item should be injected | + // Any number, defaults to 1.0. The fee amount is multiplied by this number. + // This can be used to further raise or lower the fees Connect is using. + // For example, percentile=0.95 and percentileMultiple=1.1 would use + // the 95th percentile fee, with a 10% increase + percentileMultiple: 1.1, -#### Sample Configuration {: #sample-configuration } + // Minimum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 1 + min: 200_000, -```json -{ - "showHamburgerMenu": false, - "menu": [ - { - "label": "Advance Tools", - "href": "https://portalbridge.com", - "target": "_self", - "order": 1 - } - ] + // Maximum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 100,000,000 + max: 5_000_000, + } + } + } +}; + +function App() { + return ; } ``` -### CoinGecko API Key {: #coingecko-api-key } - -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. +!!! note + Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. -### More Networks {: #more-networks } +### Wallet Set Up {: #reown-cloud-project-id } -Specify a set of extra networks to be displayed on the network selection modal, each linking to a different page, dApp, or mobile app the user will be redirected to. The following properties are accessed through the `moreNetworks` property (e.g., `moreNetworks.href`): +Your selected blockchain network determines the available wallet options when using Wormhole Connect. -|
Property
| Description | -|:--------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `href` | **Required**. Default value for missing network hrefs | -| `target` | Default value for missing network link targets. Defaults to `_self` | -| `description` | Brief description that should be displayed as a tooltip when the user hovers over a more network icon. Used as default for missing network descriptions | -| `networks[].icon` | **Required**. URL data encoded icon to display | -| `networks[].href` | Network href to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | -| `networks[].label` | **Required**. Display text | -| `networks[].name` | Unique network key. Defaults to a snake_case version of the label | -| `networks[].description` | Description value. Defaults to `moreNetworks.description` | -| `networks[].target` | href target value. Defaults to `moreNetworks.target` | -| `networks[].showOpenInNewIcon` | Disable top right open in new icon. Defaults to **true** if target is `_blank` or **false** if target is `_self` | + - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported + - For Solana, you'll see options such as Phantom, Torus, and Coin98 -??? code "View full configuration" - ```json - { - ... - "moreNetworks": { - "href": "https://example.com", - "target": "_blank", - "description": "brief description that should be displayed as tooltip when the user hovers over a more network icon", - "networks": [ - { - "icon": "https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891", - "name": "more", - "label": "More networks", - "href": "https://portalbridge.com/#/transfer", - "showOpenInNewIcon": false - } - ] - } - ... -} - ``` +The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. -### More Tokens {: #more-tokens } +If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. -Show a particular entry on the select tokens modal, redirecting the user to a different page, dApp, or mobile app. The following properties are accessed through the `moreTokens` property (e.g., `moreTokens.label`): +### CoinGecko API Key {: #coingecko-api-key } -| Property | Description | -|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `label` | **Required**. Display text | -| `href` | **Required**. URL to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | -| `target` | href target. Defaults to `_self` | +The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. -### Explorer {: #explorer } +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Enable the explorer button to allow users to search for their transactions on a given explorer, filtering by their wallet address. The following properties are accessed through the `explorer` property (e.g., `explorer.label`): +const config: WormholeConnectConfig = { + coinGeckoApiKey: 'INSERT_API_KEY', +}; -| Property | Description | -|:--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `label` | Display text. Defaults to `Transactions` | -| `href` | **Required**. URL of the explorer, for instance [https://wormholescan.io/](https://wormholescan.io/){target=\_blank}. If present, the value `address` is replaced with the connected wallet address | -| `target` | `href` target. Defaults to `_blank` | +function App() { + return ; +} +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ --- BEGIN CONTENT --- --- -title: Connect Data Configuration -description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +title: Connect Theme & UI Customization +description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. categories: Connect, Transfer --- -## Data Configuration +## Theme & UI Customization -This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. -## Get Started +### Changing the Color Scheme -Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. +You can customize Connect's color scheme by providing a `theme` prop. === "React integration" ```ts import WormholeConnect, { WormholeConnectConfig, + WormholeConnectTheme, } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - } -} + /* Your config... */ +}; - +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', +}; + +function App() { + return ; +} ``` === "Hosted integration" ```ts import WormholeConnect, { - wormholeConnectHosted, WormholeConnectConfig, + WormholeConnectTheme, + wormholeConnectHosted, } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, + /* Your config... */ +}; + +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', }; const container = document.getElementById('bridge-container'); wormholeConnectHosted(container, { config, + theme, }); ``` -!!! note - The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. +The `WormholeConnectTheme` type supports the following properties: -## Examples {: #examples } +|
Property
| Description | Example | +|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| +| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | +| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | +| `primary` | Primary color used for buttons | `"#AABBCC"` | +| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | +| `text` | Primary color used for text | `"#AABBCC"` | +| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | +| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | +| `success` | Color to display success messages in | `"#AABBCC"` | +| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | -### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } +### Toggle Hamburger Menu {: #toggle-hamburger-menu } -Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. +By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. -=== "Mainnet" +#### Add Extra Menu Entry {: #add-extra-menu-entry } - ```js - import WormholeConnect, { +By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): + +| Property | Description | +|:--------:|:-------------------------------------------:| +| `label` | Link name to show up | +| `href` | Target URL or URN | +| `target` | Anchor standard target, by default `_blank` | +| `order` | Order where the new item should be injected | + +```jsx +import WormholeConnect, { WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', + ui: { + showHamburgerMenu: false, + menu: [ + { + label: 'Advance Tools', + href: 'https://portalbridge.com', + target: '_self', + order: 1, + }, + ], }, }; function App() { return ; } - ``` +``` +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ +--- BEGIN CONTENT --- +--- +title: Connect FAQs +description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +categories: Connect, Transfer +--- + +# Wormhole Connect FAQs + +## What types of assets does Connect support? + +Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: + + - Major stablecoins like USDT and USDC (via CCTP) + - Native gas tokens such as ETH, SOL, etc. + - Cross-chain asset swaps through integrators like Mayan + +When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. + +## What chains does Connect support? + +Connect supports around 30 chains, spanning various blockchain runtimes: + + - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) + - Solana + - Move-based chains (Sui, Aptos) + +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. + +## What is gas dropoff? + +Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. + +## Can I customize Connect inside my application? + +Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. + +## Which functions or events does Connect rely on for NTT integration? + +Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. + +## Do integrators need to enable wallets like Phantom or Backpack in Connect? + +Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. + +## Which function should be modified to set priority fees for Solana transactions? + +In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. + +To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. + +The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. + +## Is there a minimum amount for bridging with CCTP or the Connect SDK? + +There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. + +Current relay fees: + +- Ethereum L1: ~4.2 USDC +- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC + +Additional notes: + +- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality +- **Frontend integrations** + - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} + - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs + + !!!note + The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/connect/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -=== "Testnet" +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ +--- BEGIN CONTENT --- +--- +title: Wormhole Connect v1.0 Migration Guide +description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. +categories: Connect, Transfer +--- - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +# Wormhole Connect v1.0 Migration Guide -const config: WormholeConnectConfig = { - // You can use Connect with testnet chains by specifying "network": - network: 'Testnet', - chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], - rpcs: { - Avalanche: 'https://rpc.ankr.com/avalanche_fuji', - BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', - }, -}; +## Overview -function App() { - return ; -} - ``` +The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. -!!! note - For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. +This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: -### Configuring Routes + - Update to the latest Connect package + - Apply configuration changes to the **`WormholeConnectConfig`** object + - Understand new routing capabilities and plugin options -By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. +These updates ensure better performance and a smoother integration experience. -#### Available Route Plugins +## Update the Connect Package -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: +To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol +Run the following command in your terminal: -In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. +```bash +npm install @wormhole-foundation/wormhole-connect@^1.0 +``` -For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. +This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. -#### Example: Offer Only CCTP Transfers +## Update the `WormholeConnectConfig` Object -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +### Summary of Breaking Changes -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; +- Chain names are now capitalized: `solana` → `Solana` +- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` +- `networks` renamed to `chains`, with capitalized names +- `routes` updated to use route plugins +- `nttGroups` removed in favor of route plugin configuration +- `tokensConfig` updated, with a new key `wrappedTokens` added +- Many UI-related properties consolidated under a top-level `ui` key +- `customTheme` and `mode` were removed, replaced by a top-level `theme` property -; -``` +These changes are explained in more detail below, with examples for easy reference. -#### Example: Offer All Default Routes and Third-Party Plugins +### Capitalize Chain Names -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +=== "v0.x" -import { myNttConfig } from './consts'; // Custom NTT configuration + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + ethereum: 'INSERT_ETH_RPC_URL', + solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` +=== "v1.x" -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + Ethereum: 'INSERT_ETH_RPC_URL', + Solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` -; -``` +You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. +### Rename `env` to `network` -### Adding Custom Tokens {: #custom-tokens } +The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. -The following section shows how to add an arbitrary token to your deployment of Connect. +=== "v0.x" -!!! note - You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. + ```typescript + const config: WormholeConnectConfig = { + env: 'testnet', + }; + ``` +=== "v1.x" -This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. + ```typescript + const config: WormholeConnectConfig = { + network: 'Testnet', + }; + ``` -See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. +If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. ```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - nativeChain: 'Ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - coinGeckoId: 'bonk', - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; +// Defaults to Mainnet +const config: WormholeConnectConfig = {}; ``` -### Whitelisting Tokens {: #whitelisting-tokens } +For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. -Connect offers a list of built-in tokens by default. You can see it below: +### Rename `networks` to `chains` -- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} -- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} +The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. -You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. +=== "v0.x" -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + ```typescript + const config: WormholeConnectConfig = { + networks: ['solana', 'ethereum'], + }; + ``` +=== "v1.x" -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: ['ETH', 'SOL', 'BONK'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; + ```typescript + const config: WormholeConnectConfig = { + chains: ['Solana', 'Ethereum'], + }; + ``` -function App() { - return ; -} -``` +### Update `routes` to Use Route Plugins -You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. +The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: [ - // Whitelist BONK on every whitelisted chain - 'BONK', - // Also whitelist USDC, specifically on Solana - ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] - ], - ... -}; + - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} + - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + +For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. + +#### Available `route` Plugins + +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: + +???- tip "`route` Plugins" + - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route + - **`CCTPRoute`** - manually redeemed CCTP route + - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route + - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) + - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route + - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route + - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array + - **`MayanRoute`** - route that offers multiple Mayan protocols + - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only + - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only + - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol -function App() { - return ; -} -``` +In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. -### User-Inputted Tokens {: #user-inputted-tokens } +For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. -As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). +Now that you know the available `route` plugins, let's explore some examples of configuring them. -If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: +#### Example: Offer Only CCTP Transfers -```jsx +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: + +```typescript import WormholeConnect, { + AutomaticCCTPRoute, WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { - ui: { - disableUserInputtedTokens: true - } + routes: [AutomaticCCTPRoute], }; -function App() { - return ; -} +; ``` -Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. - -### Transaction Settings {: #transaction-settings } +#### Example: Offer All Default Routes and Third-Party Plugins -Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -```jsx +```typescript import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; -const config: WormholeConnectConfig = { - transactionSettings: { - Solana: { - priorityFee: { - // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. - // For example, you can set percentile to 0.95 to make Connect compute the - // 95th percentile priority fee amount based on recent transactions - percentile: 0.95, - - // Any number, defaults to 1.0. The fee amount is multiplied by this number. - // This can be used to further raise or lower the fees Connect is using. - // For example, percentile=0.95 and percentileMultiple=1.1 would use - // the 95th percentile fee, with a 10% increase - percentileMultiple: 1.1, - - // Minimum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 1 - min: 200_000, +import { myNttConfig } from './consts'; // Custom NTT configuration - // Maximum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 100,000,000 - max: 5_000_000, - } - } - } +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], }; -function App() { - return ; -} +; ``` -!!! note - Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. -### Wallet Set Up {: #reown-cloud-project-id } +### Update the `tokensConfig` Structure -Your selected blockchain network determines the available wallet options when using Wormhole Connect. +In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. - - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported - - For Solana, you'll see options such as Phantom, Torus, and Coin98 +Key Changes to `tokensConfig`: -The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. + - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK + - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes + - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain -If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. +=== "v0.x" -### CoinGecko API Key {: #coingecko-api-key } + In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: { Ethereum: 18, default: 8 }, + foreignAssets: { + Solana: { + address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + decimals: 8, + }, + }, + }, + }, + }; + ``` +=== "v1.x" -const config: WormholeConnectConfig = { - coinGeckoApiKey: 'INSERT_API_KEY', -}; + In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. -function App() { - return ; -} -``` ---- END CONTENT --- + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ ---- BEGIN CONTENT --- ---- -title: Connect Theme & UI Customization -description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. -categories: Connect, Transfer ---- + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'Ethereum', // Chain name now capitalized + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: 18, // Simplified decimals field + }, + }, + wrappedTokens: { + WETH: { + Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + /* additional chains */ + }, + }, + }; + ``` -## Theme & UI Customization +### Update NTT Configuration -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. -### Changing the Color Scheme +Key changes: -You can customize Connect's color scheme by providing a `theme` prop. + - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function + - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers -=== "React integration" +This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. - ```ts +=== "v0.x" + + In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. + + ```typescript import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, -} from '@wormhole-foundation/wormhole-connect'; + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -const config: WormholeConnectConfig = { - /* Your config... */ -}; + const config: WormholeConnectConfig = { + nttGroups: { + Lido_wstETH: { + nttManagers: [ + { + chainName: 'ethereum', + address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chainName: 'bsc', + address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }, + }; + ``` +=== "v1.x" -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; + In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. -function App() { - return ; -} + ```typescript + import WormholeConnect, { + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; + + const config: WormholeConnectConfig = { + routes: [ + ...nttRoutes({ + tokens: { + Lido_wstETH: [ + { + chain: 'Ethereum', + manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', + transceiver: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chain: 'Bsc', + manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', + transceiver: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }), + /* other routes */ + ], + }; ``` -=== "Hosted integration" - - ```ts - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - wormholeConnectHosted, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - /* Your config... */ -}; - -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; + In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. -const container = document.getElementById('bridge-container'); +### Update UI Configuration -wormholeConnectHosted(container, { - config, - theme, -}); - ``` +In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. -The `WormholeConnectTheme` type supports the following properties: +Key UI changes: -|
Property
| Description | Example | -|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| -| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | -| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | -| `primary` | Primary color used for buttons | `"#AABBCC"` | -| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | -| `text` | Primary color used for text | `"#AABBCC"` | -| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | -| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | -| `success` | Color to display success messages in | `"#AABBCC"` | -| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | + - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization + - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes -### Toggle Hamburger Menu {: #toggle-hamburger-menu } +#### UI Properties -By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. +The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: -#### Add Extra Menu Entry {: #add-extra-menu-entry } + - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions + - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token + - `pageHeader` → `ui.pageHeader` - sets the title and header for the page + - `menu` → `ui.menu` - defines the menu items displayed in the interface + - `searchTx` → `ui.searchTx` - configures the transaction search functionality + - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface + - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI + - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation -By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): +Additionally, there are two new properties under `ui`: -| Property | Description | -|:--------:|:-------------------------------------------:| -| `label` | Link name to show up | -| `href` | Target URL or URN | -| `target` | Anchor standard target, by default `_blank` | -| `order` | Order where the new item should be injected | + - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" + - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel -```jsx +```typescript import WormholeConnect, { WormholeConnectConfig, } from '@wormhole-foundation/wormhole-connect'; const config: WormholeConnectConfig = { ui: { - showHamburgerMenu: false, + title: 'My Custom Bridge Example', + getHelpUrl: 'https://examplehelp.com/', menu: [ { - label: 'Advance Tools', - href: 'https://portalbridge.com', - target: '_self', - order: 1, + label: 'Support', + href: 'https://examplehelp.com/support', + target: '_blank', + order: 1, // Order of appearance in the menu + }, + { + label: 'About', + href: 'https://examplehelp.com/about', + target: '_blank', + order: 2, }, ], + showHamburgerMenu: false, }, }; - -function App() { - return ; -} ``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/build/transfers/connect/configuration/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -## Configure Connect - -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. - -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. - -!!! note - To upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for instructions. - - If you're using an older version of Wormhole Connect (v0.x), please refer to the [v0.x configuration documentation](/docs/products/connect/configuration/configuration-v0/){target=\_blank}. - -
- -- :octicons-database-16:{ .lg .middle } **Data** - - --- - Learn how to configure the networks, tokens, and routes supported by Wormhole Connect. Set up RPC endpoints, whitelist tokens, and leverage multiple bridging protocols to meet your dApp's needs. - - - [:custom-arrow: Get started](/docs/products/connect/configuration/data/) - -- :octicons-apps-16:{ .lg .middle } **Theme** +#### UI Configuration - --- +In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. - Discover how to style the Wormhole Connect widget to align with your brand. Customize colors, fonts, and UI elements to deliver a seamless user experience. +=== "v0.x" - [:custom-arrow: Explore routes](/docs/products/connect/configuration/theme/) + ```typescript + const config: WormholeConnectConfig = { + bridgeDefaults: { + fromNetwork: 'solana', + toNetwork: 'ethereum', + tokenKey: 'USDC', + requiredNetwork: 'solana', + }, + showHamburgerMenu: true, + }; + ``` +=== "v1.x" -
---- END CONTENT --- + ```typescript + const config: WormholeConnectConfig = { + ui: { + defaultInputs: { + fromChain: 'Solana', // Chain names now capitalized + toChain: 'Ethereum', + tokenKey: 'USDC', + requiredChain: 'Solana', + }, + showHamburgerMenu: true, + }, + }; + ``` -Doc-Content: https://wormhole.com/docs/products/connect/faqs/ ---- BEGIN CONTENT --- ---- -title: Connect FAQs -description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -categories: Connect, Transfer ---- +#### Remove `customTheme` and `mode` Properties -# Wormhole Connect FAQs +In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. -## What types of assets does Connect support? +Important details: -Wormhole Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: + - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect + - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes - - Major stablecoins like USDT and USDC (via CCTP) - - Native gas tokens such as ETH, SOL, etc. - - Cross-chain asset swaps through integrators like Mayan +=== "v0.x" -When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. + ```typescript + const config: WormholeConnectConfig = { + customTheme: { + primaryColor: '#4266f5', + secondaryColor: '#ff5733', + }, + mode: 'dark', + }; -## What chains does Connect support? + ; + ``` +=== "v1.x" -Connect supports around 30 chains, spanning various blockchain runtimes: + ```typescript + const theme: WormholeConnectTheme = { + mode: 'dark', // Can be dynamically changed + font: 'Arial', + button: { + primary: '#4266f5', + }, + }; - - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) - - Solana - - Move-based chains (Sui, Aptos) + ; + ``` -For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. +### Removed Configuration Properties -## What is gas dropoff? +Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. -Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. +Removed config keys: -## Can I customize Connect inside my application? + - `cta` + - `cctpWarning` + - `pageSubHeader` + - `moreTokens` + - `moreChains` + - `ethBridgeMaxAmount` + - `wstETHBridgeMaxAmount` + - `customTheme` + - `mode` -Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. +If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. -## Which functions or events does Connect rely on for NTT integration? +## Use the CDN-Hosted Version of Wormhole Connect -Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. +For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. -## Do integrators need to enable wallets like Phantom or Backpack in Wormhole Connect? +### Install and Integrate the Hosted Version -Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Wormhole Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. +1. Install the Connect package via npm: -## Which function should be modified to set priority fees for Solana transactions? + ```bash + npm install @wormhole-foundation/wormhole-connect@^1.0 + ``` -In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. +2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: -To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. + ```typescript + import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. + const container = document.getElementById('connect')!; -## Is there a minimum amount for bridging with CCTP or the Connect SDK? + wormholeConnectHosted(container); + ``` -There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. +### Example: Custom Configuration for Hosted Version -Current relay fees: +The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: -- Ethereum L1: ~4.2 USDC -- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC +```typescript +import { + wormholeConnectHosted, + MayanRoute, +} from '@wormhole-foundation/wormhole-connect'; -Additional notes: +const container = document.getElementById('connect')!; -- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality -- **Frontend integrations** - - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs +wormholeConnectHosted(container, { + config: { + routes: [MayanRoute], + eventHandler: (e) => { + console.log('Connect event', e); + }, + }, + theme: { + background: { + default: '#004547', + }, + }, +}); +``` - !!!note - The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. +In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/connect/overview/ +--- BEGIN CONTENT --- +TODO --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ @@ -11948,5296 +8512,7603 @@ This route appears if all of the following conditions are satisfied: - The relayer accepts the selected token to swap into the gas token --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ +--- BEGIN CONTENT --- +--- +title: Integrate Connect into a React DApp Tutorial +description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +categories: Connect, Transfer +--- + +# Integrate Connect into a React DApp + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. + +While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. + +## Prerequisites + +To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. +Before starting this tutorial, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use +- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} +- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees + +## Set Up Connect for Sui Transfers + +### Create a React Project + +Start by setting up your React app: + +1. Open your terminal and run the following command to create a new React app: + + ```bash + npx create-react-app connect-tutorial + ``` + +2. Navigate into the project directory: + + ```bash + cd connect-tutorial + ``` + +### Install Wormhole Connect + +Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: + +```bash +npm install @wormhole-foundation/wormhole-connect +``` + +### Integrate Connect into the Application + +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: + +=== "JavaScript" + + ```js + import logo from './logo.svg'; + import './App.css'; + import WormholeConnect from '@wormhole-foundation/wormhole-connect'; + + const config = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + }; + + function App() { + return ; + } + + export default App; + ``` + +=== "TypeScript" + + ```ts + import './App.css'; + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + } from '@wormhole-foundation/wormhole-connect'; + + function App() { + const config: WormholeConnectConfig = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + }; + + return ; + } + + export default App; + ``` + +- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment +- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche + +### Customize Wormhole Connect + +To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. + +### Run the Application + +Make sure you’re in the root directory of your React app, and run the following command to start the application: + +```bash +npm start +``` + +Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. + +## Transfer Tokens from Sui to Fuji + +Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. + +To transfer tokens from Sui to Fuji in the Wormhole Connect interface: + +1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer +2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network +3. Enter the amount of SUI tokens you wish to transfer + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) + +4. Choose to view other routes + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) + +5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) + + !!! note + It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) + +6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) + +7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) + +Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Claim Tokens on Fuji + +After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. + +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) + +Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. + +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) + +## Resources + +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. + +## Conclusion + +In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. + +By following these steps, you've learned how to: + +- Set up a React project tailored for cross-chain transfers +- Install and configure Wormhole Connect to support multiple blockchains +- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers +- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks + +With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +--- BEGIN CONTENT --- +--- +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +categories: Basics +--- + +# Get Started with Core Contracts + +## Introduction + +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. + +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. + +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. + +## Prerequisites + +To interact with the Wormhole Core Contract, you'll need the following: + +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on + +## How to Interact with Core Contracts + +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: + +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network + +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. + +### Sending Messages + +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. + +=== "EVM" + + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: + + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` -# Wormhole Connect + ??? interface "Parameters" -Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -## Build with Connect + --- -[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -## See It In Action + --- -Wormhole Connect is deployed live in several production apps. Here are a few: + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. -- [Portal Bridge](https://portalbridge.com/){target=\_blank} -- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} -- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} + ??? interface "Returns" -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" -## Next Steps + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); -
+// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); -- :octicons-tools-16:{ .lg .middle} **Get Started Now** +// Check fee and send parameters - --- +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); - Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - --- +=== "Solana" - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) + ??? interface "Parameters" + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" - --- + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) + ??? child "Type `PostMessage<'info>`" -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` - --- + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. + --- - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) + `batch_id` ++"u32"++ + + An identifier for the message batch. -
---- END CONTENT --- + --- -Doc-Content: https://wormhole.com/docs/build/transfers/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -# Wormhole Connect + --- -## Introduction {: #introduction } + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" -## Features {: #features } + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/build/transfers/connect/configuration/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -## Integrate Connect {: #integrate-connect } +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -### Import Directly into a React App {: #import-directly-into-a-react-app} +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} +### Receiving Messages -```bash -npm i @wormhole-foundation/wormhole-connect -``` +The way a message is received and handled depends on the environment. -Now you can import the React component: +=== "EVM" -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -function App() { - return ; -} -``` + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} + ??? interface "Parameters" -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; + ??? interface "Returns" -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -wormholeConnectHosted(container); -``` + ??? child "Struct `VM`" -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. + + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- - ```html - -
- - - - ``` + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: + ??? interface "Example" - ```html - -
- - - - ``` + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. + // Perform safety checks here -## Configuration {: #configuration} + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); -This is just an overview of what's possible. Check the [Configuration docs](/docs/build/transfers/connect/configuration/){target=\_blank} for details about all the configuration options. + // Your custom application logic here +} + ``` -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available +=== "Solana" -For additional information on the preceding options, check the [configuration options](/docs/build/transfers/connect/configuration/){target=\_blank} and customize your widget however you like. ---- END CONTENT --- + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. -Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ ---- BEGIN CONTENT --- ---- -title: Routes -description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -categories: Connect, Transfer ---- + Retrieve the raw message data: -## Routes Overview {: #routes-overview} + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/build/transfers/connect/configuration/){target=\_blank}. + ??? interface "Example" -Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -## Token Bridge Routes {: #token-bridge-routes} + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. +#### Validating the Emitter -#### Manual Route {: #manual-route} +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. -The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: -#### Automatic Route {: #automatic-route} +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); +``` -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -## CCTP Routes (USDC) {: #cctp-routes-usdc} - -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); -Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. +await tx.wait(); +``` -#### Manual Route {: #manual-route-cctp} +#### Additional Checks -This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -#### Automatic Route {: #automatic-route-cctp} +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? -Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. -## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} +## Source Code References -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/build/transfers/connect/configuration/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: -#### Manual Route {: #manual-route-ntt} +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} +--- END CONTENT --- -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ +--- BEGIN CONTENT --- +--- +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics +--- -#### Automatic Route {: #automatic-route-ntt} +# Wormhole Relayer -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. +## Introduction -## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -#### Automatic Route {: #automatic-route-eth} +## Get Started with the Wormhole Relayer -Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -## USDT Bridge Route {: #usdt-bridge-route} +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. +
+ ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
The components outlined in blue must be implemented.
+
-#### Automatic Route {: #automatic-route-usdt} +### Wormhole Relayer Interfaces -Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -## tBTC Route {: #tbtc-route} +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). +## Interact with the Wormhole Relayer -Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -#### Manual Route {: #manual-route-tbtc} +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. ---- END CONTENT --- +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect v1.0 Migration Guide -description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -categories: Connect, Transfer ---- +Your initial set up should resemble the following: -# Wormhole Connect v1.0 Migration Guide +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -## Overview +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. +contract Example { + IWormholeRelayer public wormholeRelayer; -This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` - - Update to the latest Connect package - - Apply configuration changes to the **`WormholeConnectConfig`** object - - Understand new routing capabilities and plugin options +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -These updates ensure better performance and a smoother integration experience. +### Send a Message -For complete documentation on the previous version of Wormhole Connect, please refer to the [Wormhole Connect guide](/docs/build/transfers/connect/){target=\_blank}. +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -## Update the Connect Package +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -Run the following command in your terminal: +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -```bash -npm install @wormhole-foundation/wormhole-connect@^1.0 +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); ``` -This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -## Update the `WormholeConnectConfig` Object +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); + +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -### Summary of Breaking Changes +### Receive a Message -- Chain names are now capitalized: `solana` → `Solana` -- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` -- `networks` renamed to `chains`, with capitalized names -- `routes` updated to use route plugins -- `nttGroups` removed in favor of route plugin configuration -- `tokensConfig` updated, with a new key `wrappedTokens` added -- Many UI-related properties consolidated under a top-level `ui` key -- `customTheme` and `mode` were removed, replaced by a top-level `theme` property +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -These changes are explained in more detail below, with examples for easy reference. +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -### Capitalize Chain Names +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. +## Delivery Guarantees -=== "v0.x" +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - ethereum: 'INSERT_ETH_RPC_URL', - solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` -=== "v1.x" +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - Ethereum: 'INSERT_ETH_RPC_URL', - Solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. +## Delivery Statuses -### Rename `env` to `network` +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -=== "v0.x" +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: - ```typescript - const config: WormholeConnectConfig = { - env: 'testnet', - }; - ``` -=== "v1.x" +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` - ```typescript - const config: WormholeConnectConfig = { - network: 'Testnet', - }; - ``` +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. -```typescript -// Defaults to Mainnet -const config: WormholeConnectConfig = {}; -``` +## Other Considerations -For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -### Rename `networks` to `chains` +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. +## Track the Progress of Messages with the Wormhole CLI -=== "v0.x" +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: - ```typescript - const config: WormholeConnectConfig = { - networks: ['solana', 'ethereum'], - }; - ``` -=== "v1.x" +=== "Mainnet" - ```typescript - const config: WormholeConnectConfig = { - chains: ['Solana', 'Ethereum'], - }; + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH ``` -### Update `routes` to Use Route Plugins +=== "Testnet" -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} +## Step-by-Step Tutorial -For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- -#### Available `route` Plugins +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ +--- BEGIN CONTENT --- +--- +title: Create Cross-Chain Contracts +description: Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. +--- -???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route - - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - - **`CCTPRoute`** - manually redeemed CCTP route - - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route - - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) - - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route - - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route - - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array - - **`MayanRoute`** - route that offers multiple Mayan protocols - - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only - - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only - - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol +# Create Cross-Chain Messaging Contracts -In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} -For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. +## Introduction -Now that you know the available `route` plugins, let's explore some examples of configuring them. +Wormhole's cross-chain messaging allows smart contracts to interact seamlessly across multiple blockchains. This enables developers to build decentralized applications that leverage the strengths of different networks, whether it's Avalanche, Celo, Ethereum, or beyond. In this tutorial, we'll explore using [Wormhole's Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} to create cross-chain contracts to send and receive messages across chains. -#### Example: Offer Only CCTP Transfers +Wormhole's messaging infrastructure simplifies data transmission, event triggering, and transaction initiation across blockchains. In this tutorial, we'll guide you through a simple yet powerful hands-on demonstration that showcases this practical capability. We'll deploy contracts on two Testnets—Avalanche Fuji and Celo Alfajores—and send messages from one chain to another. This tutorial is perfect for those new to cross-chain development and seeking hands-on experience with Wormhole's powerful toolkit. -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; +## Wormhole Overview -; -``` +We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. -#### Example: Offer All Default Routes and Third-Party Plugins +Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/build/transfers/native-token-transfers/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +## Prerequisites -import { myNttConfig } from './consts'; // Custom NTT configuration +Before starting this tutorial, ensure you have the following: -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts +- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees +- Wallet private key -; -``` +## Build Cross-Chain Messaging Contracts -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. +In this section, we'll deploy two smart contracts: one to send a message from Avalanche Fuji and another to receive it on Celo Alfajores. The contracts interact with the Wormhole relayer to transmit messages across chains. -### Update the `tokensConfig` Structure +At a high level, our contracts will: -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +1. Send a message from Avalanche to Celo using the Wormhole relayer +2. Receive and process the message on Celo, logging the content of the message -Key Changes to `tokensConfig`: +Before diving into the deployment steps, let's first break down key parts of the contracts. - - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK - - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes - - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain +### Sender Contract: MessageSender -=== "v0.x" +The `MessageSender` contract is responsible for quoting the cost of sending a message cross-chain and then sending that message. - In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. +Key functions include: - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + - **`quoteCrossChainCost`** - calculates the cost of delivering a message to the target chain using the Wormhole relayer + - **`sendMessage`** - encodes the message and sends it to the target chain and contract address using the Wormhole relayer - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: { Ethereum: 18, default: 8 }, - foreignAssets: { - Solana: { - address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - decimals: 8, - }, - }, - }, - }, - }; - ``` -=== "v1.x" +Here's the core of the contract: - In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. +```solidity +uint16 targetChain, + address targetAddress, + string memory message + ) external payable { + uint256 cost = quoteCrossChainCost(targetChain); - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + require( + msg.value >= cost, + "Insufficient funds for cross-chain delivery" + ); - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'Ethereum', // Chain name now capitalized - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: 18, // Simplified decimals field - }, - }, - wrappedTokens: { - WETH: { - Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - /* additional chains */ - }, - }, - }; - ``` + wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(message, msg.sender), + 0, + GAS_LIMIT + ); + } +``` -### Update NTT Configuration +You can find the full code for the `MessageSender.sol` below. -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +??? code "MessageSender.sol" -Key changes: + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; - - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function - - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; -This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. +contract MessageSender { + IWormholeRelayer public wormholeRelayer; + uint256 constant GAS_LIMIT = 50000; -=== "v0.x" + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } - In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. + function quoteCrossChainCost( + uint16 targetChain + ) public view returns (uint256 cost) { + (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + } - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + function sendMessage( + uint16 targetChain, + address targetAddress, + string memory message + ) external payable { + uint256 cost = quoteCrossChainCost(targetChain); - const config: WormholeConnectConfig = { - nttGroups: { - Lido_wstETH: { - nttManagers: [ - { - chainName: 'ethereum', - address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chainName: 'bsc', - address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }, - }; + require( + msg.value >= cost, + "Insufficient funds for cross-chain delivery" + ); + + wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(message, msg.sender), + 0, + GAS_LIMIT + ); + } +} ``` -=== "v1.x" - In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. +### Receiver Contract: MessageReceiver - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; +The `MessageReceiver` contract handles incoming cross-chain messages. When a message arrives, it decodes the payload and logs the message content. It ensures that only authorized contracts can send and process messages, adding an extra layer of security in cross-chain communication. - const config: WormholeConnectConfig = { - routes: [ - ...nttRoutes({ - tokens: { - Lido_wstETH: [ - { - chain: 'Ethereum', - manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', - transceiver: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chain: 'Bsc', - manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', - transceiver: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }), - /* other routes */ - ], - }; - ``` +#### Emitter Validation and Registration - In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. +In cross-chain messaging, validating the sender is essential to prevent unauthorized contracts from sending messages. The `isRegisteredSender` modifier ensures that messages can only be processed if they come from the registered contract on the source chain. This guards against malicious messages and enhances security. -### Update UI Configuration +Key implementation details include: -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. + - **`registeredSender`** - stores the address of the registered sender contract + - **`setRegisteredSender`** - registers the sender's contract address on the source chain. It ensures that only registered contracts can send messages, preventing unauthorized senders + - **`isRegisteredSender`** - restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication -Key UI changes: +```solidity - - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization - - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes +require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } -#### UI Properties + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } +``` -The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: +#### Message Processing - - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions - - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token - - `pageHeader` → `ui.pageHeader` - sets the title and header for the page - - `menu` → `ui.menu` - defines the menu items displayed in the interface - - `searchTx` → `ui.searchTx` - configures the transaction search functionality - - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface - - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI - - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation +The `receiveWormholeMessages` is the core function that processes the received message. It checks that the Wormhole relayer sent the message, decodes the payload, and emits an event with the message content. It is essential to verify the message sender to prevent unauthorized messages. -Additionally, there are two new properties under `ui`: +```solidity +bytes memory payload, + bytes[] memory, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 + ) public payable override isRegisteredSender(sourceChain, sourceAddress) { + require( + msg.sender == address(wormholeRelayer), + "Only the Wormhole relayer can call this function" + ); - - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" - - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel + // Decode the payload to extract the message + string memory message = abi.decode(payload, (string)); -```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + // Example use of sourceChain for logging + if (sourceChain != 0) { + emit SourceChainLogged(sourceChain); + } -const config: WormholeConnectConfig = { - ui: { - title: 'My Custom Bridge Example', - getHelpUrl: 'https://examplehelp.com/', - menu: [ - { - label: 'Support', - href: 'https://examplehelp.com/support', - target: '_blank', - order: 1, // Order of appearance in the menu - }, - { - label: 'About', - href: 'https://examplehelp.com/about', - target: '_blank', - order: 2, - }, - ], - showHamburgerMenu: false, - }, -}; + // Emit an event with the received message + emit MessageReceived(message); + } ``` -#### UI Configuration +You can find the full code for the `MessageReceiver.sol` below. + +??? code "MessageReceiver.sol" + + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; -In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol"; -=== "v0.x" +contract MessageReceiver is IWormholeReceiver { + IWormholeRelayer public wormholeRelayer; + address public registrationOwner; - ```typescript - const config: WormholeConnectConfig = { - bridgeDefaults: { - fromNetwork: 'solana', - toNetwork: 'ethereum', - tokenKey: 'USDC', - requiredNetwork: 'solana', - }, - showHamburgerMenu: true, - }; - ``` -=== "v1.x" + // Mapping to store registered senders for each chain + mapping(uint16 => bytes32) public registeredSenders; - ```typescript - const config: WormholeConnectConfig = { - ui: { - defaultInputs: { - fromChain: 'Solana', // Chain names now capitalized - toChain: 'Ethereum', - tokenKey: 'USDC', - requiredChain: 'Solana', - }, - showHamburgerMenu: true, - }, - }; - ``` + event MessageReceived(string message); + event SourceChainLogged(uint16 sourceChain); -#### Remove `customTheme` and `mode` Properties + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + registrationOwner = msg.sender; // Set contract deployer as the owner + } -In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } -Important details: + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } - - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect - - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes + // Update receiveWormholeMessages to include the source address check + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 + ) public payable override isRegisteredSender(sourceChain, sourceAddress) { + require( + msg.sender == address(wormholeRelayer), + "Only the Wormhole relayer can call this function" + ); -=== "v0.x" + // Decode the payload to extract the message + string memory message = abi.decode(payload, (string)); - ```typescript - const config: WormholeConnectConfig = { - customTheme: { - primaryColor: '#4266f5', - secondaryColor: '#ff5733', - }, - mode: 'dark', - }; + // Example use of sourceChain for logging + if (sourceChain != 0) { + emit SourceChainLogged(sourceChain); + } - ; + // Emit an event with the received message + emit MessageReceived(message); + } +} ``` -=== "v1.x" - ```typescript - const theme: WormholeConnectTheme = { - mode: 'dark', // Can be dynamically changed - font: 'Arial', - button: { - primary: '#4266f5', - }, - }; +## Deploy Contracts - ; - ``` +This section will guide you through deploying the cross-chain messaging contracts on the Avalanche Fuji and Celo Alfajores Testnets. Follow these steps to get your contracts up and running. -### Removed Configuration Properties +### Deployment Tools +We use _Foundry_ to deploy our smart contracts. However, you can use any tool you're comfortable with, such as: -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. + - [Remix](https://remix.ethereum.org/){target=\_blank} for a browser-based IDE + - [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#installation){target=\_blank} for a more extensive JavaScript/TypeScript workflow + - [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for a CLI-focused experience with built-in scripting and testing features -Removed config keys: +The contracts and deployment steps remain the same regardless of your preferred tool. The key is to ensure you have the necessary Testnet funds and are deploying to the right networks. - - `cta` - - `cctpWarning` - - `pageSubHeader` - - `moreTokens` - - `moreChains` - - `ethBridgeMaxAmount` - - `wstETHBridgeMaxAmount` - - `customTheme` - - `mode` +### Repository Setup -If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. +To get started with cross-chain messaging using Wormhole, first clone the [GitHub repository](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank}. This repository includes everything you need to deploy, interact, and test the message flow between chains. -## Use the CDN-Hosted Version of Wormhole Connect +This demo focuses on using the scripts, so it's best to take a look at them, starting with `deploySender.ts`, `deployReceiver.ts`, and `sendMessage.ts`. -For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. +To configure the dependencies properly, run the following command: -### Install and Integrate the Hosted Version +```bash +npm install +``` -1. Install the Connect package via npm: +The repository includes: - ```bash - npm install @wormhole-foundation/wormhole-connect@^1.0 - ``` +- Two Solidity contracts: -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: + - **`MessageSender.sol`** - contract that sends the cross-chain message from Avalanche + - **`MessageReceiver.sol`** - contract that receives the cross-chain message on Celo - ```typescript - import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; +- Deployment scripts located in the `script` directory: - const container = document.getElementById('connect')!; + - **`deploySender.ts`** - deploys the `MessageSender` contract to Avalanche + - **`deployReceiver.ts`** - deploys the `MessageReceiver` contract to Celo + - **`sendMessage.ts`** - sends a message from Avalanche to Celo - wormholeConnectHosted(container); +- Configuration files and ABI JSON files for easy deployment and interaction: + + - **`chains.json`** - configuration file that stores key information for the supported Testnets, including the Wormhole relayer addresses, RPC URLs, and chain IDs. You likely won't need to modify this file unless you're working with different networks + + - A dedicated `interfaces` directory inside the `src` folder for TypeScript type definitions: + + - **`ChainsConfig.ts`** - defines the types for the `chains.json` configuration file + - **`DeployedContracts.ts`** - contains types for deployed contract addresses and related information + - **`MessageJsons.ts`** - includes types for ABI and bytecode JSONs used by the deployment scripts + - **`index.ts`** - serves as an export aggregator for the interfaces, simplifying imports in other files + +### Important Setup Steps + +1. **Add your private key** - create a `.env` file in the root of the project and add your private key: + + ```env + touch .env ``` -### Example: Custom Configuration for Hosted Version + Inside `.env`, add your private key in the following format: -The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: + ```env + PRIVATE_KEY=INSERT_PRIVATE_KEY + ``` -```typescript -import { - wormholeConnectHosted, - MayanRoute, -} from '@wormhole-foundation/wormhole-connect'; +2. **Compile the contracts** - ensure everything is set up correctly by compiling the contracts: -const container = document.getElementById('connect')!; + ```bash + forge build + ``` -wormholeConnectHosted(container, { - config: { - routes: [MayanRoute], - eventHandler: (e) => { - console.log('Connect event', e); - }, - }, - theme: { - background: { - default: '#004547', - }, - }, -}); -``` +The expected output should be similar to this: -In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). ---- END CONTENT --- +
+forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! + +
-Doc-Content: https://wormhole.com/docs/build/transfers/ ---- BEGIN CONTENT --- ---- -title: Multichain Transfers -description: This section guides you through using Wormhole products to securely and efficiently transfer assets and messages across multiple blockchains. ---- +### Deployment Process -# Multichain Transfers +Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the following key tasks: -Wormhole transfer products offer multiple asset transfer options to meet developer needs and use cases. These sections include guides to integrate and use Wormhole transfer products to securely and efficiently transfer assets and messages across multiple blockchains. +1. **Load configuration and contract details** - each script begins by loading the necessary configuration details, such as the network's RPC URL and the contract's ABI and bytecode. This information is essential for deploying the contract to the correct blockchain network -Use the following links to jump directly to each Wormhole transfer product page or continue on for a feature-based product comparison. + === "`chains.json`" -- [**Connect**](/docs/build/transfers/connect/) - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup -- [**Native Token Transfers (NTT)**](/docs/build/transfers/native-token-transfers/) - a mechanism to transfer native tokens cross-chain seamlessly without converting to a wrapped asset -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism -- [**Settlement**](/docs/build/transfers/settlement/) - an intent protocol suite for fast multichain transfers, optimizing liquidity flows and interoperability without relying on traditional bridging methods + ```json + { + "chains": [ + { + "description": "Avalanche testnet fuji", + "chainId": 6, + "rpc": "https://api.avax-test.network/ext/bc/C/rpc", + "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", + "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", + "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" + }, + { + "description": "Celo Testnet", + "chainId": 14, + "rpc": "https://alfajores-forno.celo-testnet.org", + "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", + "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", + "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" + } + ] +} + ``` + + === "`deploySender.ts`" -## Products By Feature + ```typescript + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -While all of these products handle token transfers, there are additional features to consider when selecting the best fit for your project needs. + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); + ``` -
+ === "`deployReceiver.ts`" -- :octicons-file-code-16:{ .lg .middle } **Message Payload** + ```typescript + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); - --- + // Get the Celo Testnet configuration + const celoChain = chains.chains.find((chain) => + chain.description.includes('Celo Testnet') + ); + ``` - Send message payloads for social platforms, NFTs, and more with Token Bridge's lock and mint wrapped token mechanism. + !!! note + The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/contract-addresses/){target=\_blank}. - [:custom-arrow: Discover Token Bridge](/docs/build/transfers/token-bridge/) +2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction -- :octicons-file-code-16:{ .lg .middle } **Native Assets** + === "`deploySender.ts`" - --- + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` - Eliminate the need for wrapped tokens and issue native multichain assets with Native Token Transfers (NTT). + === "`deployReceiver.ts`" - [:custom-arrow: Discover Native Token Transfers](/docs/build/transfers/native-token-transfers/) + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` +3. **Deploy the contract** - the contract is deployed to the network specified in the configuration. Upon successful deployment, the contract address is returned, which is crucial for interacting with the contract later on -- :octicons-file-code-16:{ .lg .middle } **Speed at Scale** + === "`deploySender.ts`" - --- + ```typescript + avalancheChain.wormholeRelayer + ); + await senderContract.waitForDeployment(); + ``` - Unleash institutional-scale digital asset settlement with Wormhole Settlement's intent-based asset transfers and liquidity layer. + === "`deployReceiver.ts`" - [:custom-arrow: Discover Settlement](/docs/build/transfers/settlement/) + ```typescript + celoChain.wormholeRelayer + ); + await receiverContract.waitForDeployment(); + ``` -- :octicons-gear-16:{ .lg .middle } **Plug-and-Play UI** +4. **Register the `MessageSender` on the target chain** - after you deploy the `MessageReceiver` contract on the Celo Alfajores network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed - --- + This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract - Add Wormhole's bridge UI to your dApp, no smart contract development required, with Connect. + ```typescript + const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; + if (!avalancheSenderAddress) { + throw new Error('Avalanche MessageSender address not found.'); + } - [:custom-arrow: Discover Connect](/docs/build/transfers/connect/) + // Define the source chain ID for Avalanche Fuji + const sourceChainId = 6; -
+ // Call setRegisteredSender on the MessageReceiver contract + const tx = await (receiverContract as any).setRegisteredSender( + sourceChainId, + ethers.zeroPadValue(avalancheSenderAddress, 32) + ); + await tx.wait(); + ``` -## Additional Resources +You can find the full code for the `deploySender.ts` and `deployReceiver.ts` below. -
+??? code "deploySender.ts" -- :octicons-tools-16:{ .lg .middle } **Product Comparison** + ```typescript + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { + ChainsConfig, + DeployedContracts, + MessageSenderJson, +} from './interfaces'; - --- +dotenv.config(); - Compare Wormhole's cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +async function main(): Promise { + // Load the chain configuration from JSON + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); - [:custom-arrow: Compare Products](/docs/build/start-building/products/) + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); + if (!avalancheChain) { + throw new Error( + 'Avalanche testnet configuration not found in chains.json.' + ); + } -- :octicons-book-16:{ .lg .middle } **Use Cases** + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - --- + // Load the ABI and bytecode of the MessageSender contract + const messageSenderJson: MessageSenderJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); - Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. + const { abi, bytecode } = messageSenderJson; - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) + // Create a ContractFactory for MessageSender + const MessageSender = new ethers.ContractFactory(abi, bytecode, wallet); + // Deploy the contract using the Wormhole Relayer address for Avalanche Fuji + const senderContract = await MessageSender.deploy( + avalancheChain.wormholeRelayer + ); + await senderContract.waitForDeployment(); -
---- END CONTENT --- + console.log('MessageSender deployed to:', senderContract.target); // `target` is the address in ethers.js v6 -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ ---- BEGIN CONTENT --- ---- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer ---- + // Update the deployedContracts.json file + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/deployedContracts.json' + ); + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); -# NTT CLI Commands + deployedContracts.avalanche = { + MessageSender: senderContract.target as any, + deployedAt: new Date().toISOString(), + }; -## Introduction + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); +} -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](/docs/build/transfers/native-token-transfers/deployment-process/installation/#installation){target=\_blank} to set it up before proceeding. +??? code "deployReceiver.ts" -## Table of Commands + ```typescript + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { + ChainsConfig, + DeployedContracts, + MessageReceiverJson, +} from './interfaces'; -The following table lists the available NTT CLI commands, descriptions, and examples. +dotenv.config(); -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +async function main(): Promise { + // Load the chain configuration from the JSON file + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -### General Commands + // Get the Celo Testnet configuration + const celoChain = chains.chains.find((chain) => + chain.description.includes('Celo Testnet') + ); + if (!celoChain) { + throw new Error('Celo Testnet configuration not found.'); + } -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(celoChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); -### Configuration Commands + // Load the ABI and bytecode of the MessageReceiver contract + const messageReceiverJson: MessageReceiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/MessageReceiver.sol/MessageReceiver.json' + ), + 'utf8' + ) + ); -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| + const { abi, bytecode } = messageReceiverJson; -### Solana Commands + // Create a ContractFactory for MessageReceiver + const MessageReceiver = new ethers.ContractFactory(abi, bytecode, wallet); -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| + // Deploy the contract using the Wormhole Relayer address for Celo Testnet + const receiverContract = await MessageReceiver.deploy( + celoChain.wormholeRelayer + ); + await receiverContract.waitForDeployment(); -## Where to Go Next + console.log('MessageReceiver deployed to:', receiverContract.target); // `target` is the contract address in ethers.js v6 -
+ // Update the deployedContracts.json file + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/deployedContracts.json' + ); + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); + // Retrieve the address of the MessageSender from the deployedContracts.json file + const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; + if (!avalancheSenderAddress) { + throw new Error('Avalanche MessageSender address not found.'); + } -- :octicons-gear-16:{ .lg .middle } **Configure NTT** + // Define the source chain ID for Avalanche Fuji + const sourceChainId = 6; - --- + // Call setRegisteredSender on the MessageReceiver contract + const tx = await (receiverContract as any).setRegisteredSender( + sourceChainId, + ethers.zeroPadValue(avalancheSenderAddress, 32) + ); + await tx.wait(); - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. + console.log( + `Registered MessageSender (${avalancheSenderAddress}) for Avalanche chain (${sourceChainId})` + ); - [:custom-arrow: Configure your NTT deployment](/docs/build/transfers/native-token-transfers/configuration/) + deployedContracts.celo = { + MessageReceiver: receiverContract.target as any, + deployedAt: new Date().toISOString(), + }; -- :octicons-question-16:{ .lg .middle } **NTT FAQs** + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); +} - --- +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +### Deploy the Sender Contract - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +The sender contract will handle quoting and sending messages cross-chain. -
---- END CONTENT --- +1. Run the following command to deploy the sender contract: -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Access Control -description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. -categories: NTT, Transfer ---- + ```bash + npm run deploy:sender + ``` -## Owner and Pauser Roles +2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\_blank} -Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). +
+npm run deploy:sender + > wormhole-cross-chain@1.0.0 deploy:sender + > node script/deploySender.ts + MessageSender deployed to: 0xf5c474f335fFf617fA6FD04DCBb17E20ee0cEfb1 + +
-NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. -- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused -- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts +### Deploy the Receiver Contract -You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. +The receiver contract listens for cross-chain messages and logs them when received. -```json -{ - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": true, // set to true to pause the contract - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - //... - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } -} -``` +1. Deploy the receiver contract with this command: + + ```bash + npm run deploy:receiver + ``` -!!! note - While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. +2. After deployment, note down the contract address. You may check the contract on the [Celo Alfajores Explorer](https://alfajores.celoscan.io/){target=\_blank}. -The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. -Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. ---- END CONTENT --- +## Send a Cross-Chain Message -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/configuration/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) - Configuration -description: This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -categories: NTT, Transfer ---- +Now that both the sender and receiver contracts are deployed, let's move on to the next exciting step: sending a cross-chain message from Avalanche Fuji to Celo Alfajores. -# Configure Native Token Transfers (NTT) +In this example, we will use the `sendMessage.ts` script to transmit a message from the sender contract on Avalanche to the receiver contract on Celo. The script uses [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} to interact with the deployed contracts, calculate the cross-chain cost dynamically, and handle the transaction. -## Get Started +Let's break down the script step by step. -This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +1. **Load configuration files** -
+ 1. **`chains.json`** - contains details about the supported Testnet chains, such as RPC URLs and relayer addresses + 2. **`deployedContracts.json`** - stores the addresses of the deployed sender and receiver contracts. This file is dynamically updated when contracts are deployed, but users can also manually add their own deployed contract addresses if needed -- :octicons-clock-16:{ .lg .middle } **Rate Limiting** + ```typescript + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); - --- + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/deployedContracts.json'), + 'utf8' + ) + ); + ``` - Discover options for configuring rate limits and how queueing effects transaction flow. +2. **Configure the provider and signer** - the script first reads the chain configurations and extracts the contract addresses. One essential step in interacting with a blockchain is setting up a _provider_. A provider is your connection to the blockchain network. It allows your script to interact with the blockchain, retrieve data, and send transactions. In this case, we're using a JSON-RPC provider - [:custom-arrow: Explore rate limit options](/docs/products/native-token-transfers/configuration/rate-limiting/) + Next, we configure the wallet, which will be used to sign transactions. The wallet is created using the private key and the provider. This ensures that all transactions sent from this wallet are broadcast to the Avalanche Fuji network: + + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` -- :octicons-unlock-16:{ .lg .middle } **Access Control** + After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it: - --- + ```typescript + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); + ``` - Learn more about access control, including why you should consider setting a separate Pauser address as part of your development security plan. +3. **Set up the message details** - the next part of the script defines the target chain (Celo) and the target address (the receiver contract on Celo): - [:custom-arrow: Explore access control roles](/docs/products/native-token-transfers/configuration/access-control/) + ```typescript + const targetAddress = deployedContracts.celo.MessageReceiver; + ``` -
---- END CONTENT --- + You can customize the message that will be sent across chains: -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Rate Limiting -description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. -categories: NTT, Transfer ---- + ```typescript + + ``` -## Introduction +4. **Estimate cross-chain cost** - before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function: -The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. + ```typescript + + ``` -If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. + This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message. -You can configure the following limits on every chain where NTT is deployed directly using the manager: +5. **Send a message** - with everything set up, the message is sent using the `sendMessage` function: -- **Sending limit** - a single outbound limit for sending tokens from the chain -- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum + ```typescript + targetChain, + targetAddress, + message, + { + value: txCost, + } + ); + ``` -Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. + After sending, the script waits for the transaction to be confirmed: -## Update Rate Limits + ```typescript + + ``` -To configure or update the sending and receiving rate limits, follow these steps: +6. **Run the script** - to send the message, run the following command: -1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts + ```bash + npm run send:message + ``` -2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed +If everything is set up correctly, the message will be sent from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. You can monitor the transaction and verify that the message was received on Celo using the [Wormhole Explorer](https://wormholescan.io/#/?network=TESTNET){target=\_blank}. - ```json - "limits": { - "outbound": "1000.000000000000000000", - "inbound": { - "Ethereum": "100.000000000000000000", - "Arbitrum": "50.000000000000000000" - } - } - ``` +The console should output something similar to this: - - **`outbound`** - sets the maximum tokens allowed to leave the chain - - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains +
+npm run send:message + > wormhole-cross-chain@1.0.0 send:message + > node script/sendMessage.ts +Sender Contract Address: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 +Receiver Contract Address: 0x692550997C252cC5044742D1A2BD91E4f4b46D39 +... +Transaction sent, waiting for confirmation... +... +Message sent! Transaction hash: + 0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6 +You may see the transaction status on the Wormhole Explorer: + https://wormholescan.io/#/tx/0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6?network=TESTNET + +
-3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain +You can find the full code for the `sendMessage.ts` below. - ```bash - ntt push - ``` +??? code "sendMessage.ts" -4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status + ```solidity + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { ChainsConfig, DeployedContracts } from './interfaces'; - ```bash - ntt status - ``` +dotenv.config(); -???- note "`deployment.json` example" - ```json - { - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": false, - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", - "transceivers": { - "threshold": 1, - "wormhole": { - "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - }, - "limits": { - "outbound": "184467440737.095516150000000000", - "inbound": { - "ArbitrumSepolia": "500.000000000000000000" - } - }, - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } - } - ``` +async function main(): Promise { + // Load the chain configuration and deployed contract addresses + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -## Queuing Mechanism + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/deployedContracts.json'), + 'utf8' + ) + ); -When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: + console.log( + 'Sender Contract Address: ', + deployedContracts.avalanche.MessageSender + ); + console.log( + 'Receiver Contract Address: ', + deployedContracts.celo.MessageReceiver + ); + console.log('...'); -- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer -- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); -Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. + if (!avalancheChain) { + throw new Error( + 'Avalanche testnet configuration not found in chains.json.' + ); + } -## Cancel Flows + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); -If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. ---- END CONTENT --- + // Load the ABI of the MessageSender contract + const messageSenderJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers EVM Deployment -description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer ---- + const abi = messageSenderJson.abi; -# Native Token Transfers (NTT) EVM Development + // Create a contract instance for MessageSender + const MessageSender = new ethers.Contract( + deployedContracts.avalanche.MessageSender, // Automatically use the deployed address + abi, + wallet + ); -## Deploy Your Token and Ensure Compatibility + // Define the target chain and target address (the Celo receiver contract) + const targetChain = 14; // Wormhole chain ID for Celo Alfajores + const targetAddress = deployedContracts.celo.MessageReceiver; -If you still need to do so, deploy the token contract to the destination or spoke chains. + // The message you want to send + const message = 'Hello from Avalanche to Celo!'; -### Requirements for Token Deployment + // Dynamically quote the cross-chain cost + const txCost = await MessageSender.quoteCrossChainCost(targetChain); -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. + // Send the message (make sure to send enough gas in the transaction) + const tx = await MessageSender.sendMessage( + targetChain, + targetAddress, + message, + { + value: txCost, + } + ); -#### Burn-and-Mint Mode + console.log('Transaction sent, waiting for confirmation...'); + await tx.wait(); + console.log('...'); -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: + console.log('Message sent! Transaction hash:', tx.hash); + console.log( + `You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/${tx.hash}?network=TESTNET` + ); +} -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. +## Conclusion -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; +You're now fully equipped to build cross-chain contracts using the Wormhole protocol! With this tutorial, you've learned how to: -interface INttToken { - /// @notice Error when the caller is not the minter. - /// @dev Selector 0x5fb5729e. - /// @param caller The caller of the function. - error CallerNotMinter(address caller); +- Deploy sender and receiver contracts on different Testnets +- Send a cross-chain message from one blockchain to another +- Monitor the status of your cross-chain transactions using the Wormhole Explorer and Wormhole-Solidity-SDK +--- END CONTENT --- - /// @notice Error when the minter is the zero address. - /// @dev Selector 0x04a208c7. - error InvalidMinterZeroAddress(); +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-token-contracts/ +--- BEGIN CONTENT --- +--- +title: Cross-Chain Token Transfers +description: Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. +--- - /// @notice Error when insufficient balance to burn the amount. - /// @dev Selector 0xcf479181. - /// @param balance The balance of the account. - /// @param amount The amount to burn. - error InsufficientBalance(uint256 balance, uint256 amount); +# Create Cross-Chain Token Transfer Contracts - /// @notice The minter has been changed. - /// @dev Topic0 - /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. - /// @param newMinter The new minter. - event NewMinter(address previousMinter, address newMinter); +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} - // NOTE: the `mint` method is not present in the standard ERC20 interface. - function mint(address account, uint256 amount) external; +## Introduction - // NOTE: the `setMinter` method is not present in the standard ERC20 interface. - function setMinter(address newMinter) external; +In this tutorial, you'll learn how to create a simple cross-chain token transfer system using the Wormhole protocol via the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. We'll guide you through building and deploying smart contracts that enable seamless token transfers of IERC-20 tokens between blockchains. Whether you're a developer looking to explore cross-chain applications or just interested in the Wormhole protocol, this guide will help you understand the fundamentals. - // NOTE: NttTokens in `burn` mode require the `burn` method to be present. - // This method is not present in the standard ERC20 interface, but is - // found in the `ERC20Burnable` interface. - function burn(uint256 amount) external; -} - ``` +By the end of this tutorial, you'll have a working cross-chain token transfer system built with the powerful tools provided by the Wormhole Solidity SDK, which you can further customize and integrate into your projects. -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. +## Prerequisites -#### Hub-and-Spoke Mode +Before you begin, ensure you have the following: -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts +- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees +- [USDC Testnet](https://faucet.circle.com/){target=\_blank} tokens on Avalanche-Fuji or/and Celo-Alfajores for cross-chain transfer +- Wallet private key - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers +## Valid Tokens for Transfer -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +It's important to note that this tutorial leverages [Wormhole's TokenBridge](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/TokenBridge.sol){target=\_blank} to transfer tokens between chains. So, the tokens you'd like to transfer must have an attestation on the `TokenBridge` contract of the target blockchain. -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. +To simplify this process, we've included a tool for verifying if a token has an attestation on the target chain. This tool uses the [`wrappedAsset`](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/BridgeGetters.sol#L50-L52){target=\_blank} function from the `TokenBridge` contract. If the token has an attestation, the `wrappedAsset` function returns the address of the wrapped token on the target chain; otherwise, it returns the zero address. -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. +???- tip "Check Token Attestation" + 1. Clone the [repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} and navigate to the project directory: + ```bash + git clone https://github.com/wormhole-foundation/demo-cross-chain-token-transfer.git + cd cross-chain-token-transfers + ``` + 2. Install the dependencies: + ```bash + npm install + ``` + + 3. Run the script to check token attestation: + ```bash + npm run verify + ``` -For more detailed information, see the [Deployment Models](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank} page. + 4. Follow the prompts: -### Key Differences Between Modes + 1. Enter the RPC URL of the target chain + 2. Enter the `TokenBridge` contract address on the target chain + 3. Enter the token contract address on the source chain + 4. Enter the source chain ID - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency + 5. The expected output when the token has an attestation: + +
+npm run verify + > cross-chain-token-transfer@1.0.0 verify + > npx ts-node script/check-attestation.ts + + Enter the TARGET chain RPC URL: https://alfajores-forno.celo-testnet.org + Enter the Token Bridge contract address on the TARGET chain: 0x05...E153 + Enter the token contract address on the SOURCE chain: 0x54...bc65 + Enter the SOURCE chain ID: 6 + The token is attested on the target chain. Wrapped token address: 0xDDB349c976cA2C873644F21f594767Eb5390C831 + +
+ + Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process. -## Deploy NTT +## Project Setup -Create a new NTT project: +Let's start by initializing a new Foundry project. This will set up a basic structure for our smart contracts. -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` +1. Open your terminal and run the following command to initialize a new Foundry project: + + ```bash + forge init cross-chain-token-transfers + ``` -Initialize a new `deployment.json` file specifying the network: + This will create a new directory named `cross-chain-token-transfers` with a basic project structure. This also initializes a new `git` repository. -=== "Testnet" +2. Navigate into the newly created project directory: ```bash - ntt init Testnet + cd cross-chain-token-transfers ``` -=== "Mainnet" +3. Install the Wormhole Solidity SDK: ```bash - ntt init Mainnet + forge install wormhole-foundation/wormhole-solidity-sdk ``` -Ensure you have set up your environment correctly: + To ease development, we'll use the Wormhole Solidity SDK, which provides useful helpers for cross-chain development. + This SDK includes the `TokenSender` and `TokenReceiver` abstract classes, which simplify sending and receiving tokens across chains. -```bash -export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY -``` +## Build Cross-Chain Contracts -Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: +In this section, we'll build two smart contracts to send tokens from a source chain and receive them on a target chain. These contracts will interact with the Wormhole protocol to facilitate secure and seamless cross-chain token transfers. -```bash -# Set scanner API Keys as environment variables -export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY -export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY +At a high level, our contracts will: -# Add each chain -# The contracts will be automatically verified using the scanner API keys above -ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -``` +1. Send tokens from one blockchain to another using the Wormhole protocol +2. Receive and process the tokens on the target chain, ensuring they are correctly transferred to the intended recipient -While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. +Before diving into the contract implementation steps, let’s first break down the key parts of the contracts. -The `ntt add-chain` command takes the following parameters: +### Sender Contract: CrossChainSender -- Name of each chain -- Version of NTT to deploy (use `--latest` for the latest contract versions) -- Mode (either `burning` or `locking`) -- Your token contract address +The `CrossChainSender` contract calculates the cost of sending tokens across chains and then facilitates the actual token transfer. -The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. +Let's start writing the `CrossChainSender` contract: -## Configure NTT +1. Create a new file named `CrossChainSender.sol` in the `/src` directory: + + ```bash + touch src/CrossChainSender.sol + ``` -The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: +2. Open the file. First, we'll start with the imports and the contract setup: -- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain -- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: + ```solidity + pragma solidity ^0.8.13; - For Solana, the limits are set with 9 decimal places: - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - } - ``` +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; - For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: - ```json - "inbound": { - "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia - } - ``` +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; - This initial configuration ensures that the rate limits are correctly represented for each chain's token precision - -- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + ``` -After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. + This sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. -## Set Token Minter to NTT Manager + With the contract structure in place, define the following functions within its body to enable multichain token transfers. -The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. +3. Next, let's add a function that estimates the cost of sending tokens across chains: -!!! note - The required NTT Manager address can be found in the `deployment.json` file. + ```solidity + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); -- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function - ```json - cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + cost = deliveryCost + wormhole.messageFee(); + } ``` -- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter + This function, `quoteCrossChainDeposit`, helps calculate the cost of transferring tokens to a different chain. It factors in the delivery cost and the cost of publishing a message via the Wormhole protocol. -By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. +4. Finally, we'll add the function that sends the tokens across chains: -!!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} page. ---- END CONTENT --- + ```solidity + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Solana Deployment -description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer ---- + IERC20(token).transferFrom(msg.sender, address(this), amount); -# Deploy Native Token Transfers on Solana + bytes memory payload = abi.encode(recipient); -[Native Token Transfers (NTT)](/docs/learn/transfers/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } + ``` -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. + This `sendCrossChainDeposit` function is where the actual token transfer happens. It sends the tokens to the recipient on the target chain using the Wormhole protocol. -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. +Here’s a breakdown of what happens in each step of the `sendCrossChainDeposit` function: -## Prerequisites +1. **Cost calculation** - the function starts by calculating the cost of the cross-chain transfer using `quoteCrossChainDeposit`(`targetChain`). This cost includes both the delivery fee and the Wormhole message fee. The `sendCrossChainDeposit` function then checks that the user has sent the correct amount of Ether to cover this cost (`msg.value`) -Before deploying NTT on Solana, ensure you have the following: +2. **Token transfer to contract** - the next step is to transfer the specified amount of tokens from the user to the contract itself using `IERC-20(token).transferFrom(msg.sender, address(this), amount)`. This ensures that the contract has custody of the tokens before initiating the cross-chain transfer -- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} -- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** -- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +3. **Payload encoding** - The recipient's address on the target chain is encoded into a payload using `abi.encode(recipient)`. This payload will be sent along with the token transfer, so the target contract knows who should receive the tokens on the destination chain -Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. +4. **Cross-chain transfer** - the `sendTokenWithPayloadToEvm` function is called to initiate the cross-chain token transfer. This function: + - Specifies the `targetChain` (the Wormhole chain ID of the destination blockchain). + - Sends the `targetReceiver` contract address on the target chain that will receive the tokens. + - Attaches the payload containing the recipient's address. + - Sets the `GAS_LIMIT` for the transaction. + - Passes the token `address` and `amount` to transfer. -## Overview of the Deployment Process + This triggers the Wormhole protocol to handle the cross-chain messaging and token transfer, ensuring the tokens and payload reach the correct destination on the target chain. -Deploying NTT with the CLI on Solana follows a structured process: +You can find the complete code for the `CrossChainSender.sol` below. -1. **Choose your token setup**: +??? code "MessageSender.sol" - - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section - - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; - ???- interface "Create and Mint SPL Tokens" - This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; - 1. **Generate a Solana key pair** - run the following command to create a new wallet: +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; - ```bash - solana-keygen grind --starts-with w:1 --ignore-case - ``` + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: + // Function to get the estimated cost for cross-chain deposit + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); - ```bash - solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON - ``` + cost = deliveryCost + wormhole.messageFee(); + } - 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: + // Function to send tokens and payload across chains + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); - === "Mainnet" - ```bash - solana config set -um - ``` + IERC20(token).transferFrom(msg.sender, address(this), amount); - === "Testnet" - ```bash - solana config set -ut - ``` + bytes memory payload = abi.encode(recipient); - === "Devnet" - ```bash - solana config set -ud - ``` + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` - 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: +### Receiver Contract: CrossChainReceiver - ```bash - solana airdrop 2 - solana balance - ``` +The `CrossChainReceiver` contract is designed to handle the receipt of tokens and payloads from another blockchain. It ensures that the tokens are correctly transferred to the designated recipient on the receiving chain. - 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} +Let's start writing the `CrossChainReceiver` contract: - ```bash - cargo install spl-token-cli - ``` +1. Create a new file named `CrossChainReceiver.sol` in the `/src` directory: - 6. **Create a new SPL token** - initialize the token on Solana + ```bash + touch src/CrossChainReceiver.sol + ``` - ```bash - spl-token create-token - ``` +2. Open the file. First, we'll start with the imports and the contract setup: - 7. **Create a token account** - generate an account to hold the token + ```solidity + pragma solidity ^0.8.13; - ```bash - spl-token create-account INSERT_TOKEN_ADDRESS - ``` +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; - 8. **Mint tokens** - send 1000 tokens to the created account +contract CrossChainReceiver is TokenReceiver { + // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract - ```bash - spl-token mint INSERT_TOKEN_ADDRESS 1000 - ``` + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + ``` - !!! note - NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. + Similar to the `CrossChainSender` contract, this sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. + +3. Next, let's add a function inside the contract to handle receiving the payload and tokens: -2. **Choose your [deployment model](/docs/learn/transfers/native-token-transfers/deployment/){target=\_blank}**: + ```solidity + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + require(receivedTokens.length == 1, "Expected 1 token transfer"); - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); -3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } + ``` -Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. + This `receivePayloadAndTokens` function processes the tokens and payload sent from another chain, decodes the recipient address, and transfers the tokens to them using the Wormhole protocol. This function also validates the emitter (`sourceAddress`) to ensure the message comes from a trusted sender. -By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. + This function ensures that: -## Set Up NTT + - It only processes one token transfer at a time + - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract + - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface -To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. +After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. -The [NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +??? tip "Understanding the `TokenReceived` Struct" -1. **Create a new NTT project** - set up a deployment workspace + Let’s delve into the fields provided to us in the `TokenReceived` struct: - ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME + ```solidity + struct TokenReceived { + bytes32 tokenHomeAddress; + uint16 tokenHomeChain; + address tokenAddress; + uint256 amount; + uint256 amountNormalized; +} ``` -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings - - === "Mainnet" - - ```bash - ntt init Mainnet - ``` + - **`tokenHomeAddress`** - the original address of the token on its native chain. This is the same as the token field in the call to `sendTokenWithPayloadToEvm` unless the original token sent is a Wormhole-wrapped token. In that case, this will be the address of the original version of the token (on its native chain) in Wormhole address format (left-padded with 12 zeros) - === "Testnet" + - **`tokenHomeChain`** - the Wormhole chain ID corresponding to the home address above. This will typically be the source chain unless the original token sent is a Wormhole-wrapped asset, which will be the chain of the unwrapped version of the token - ```bash - ntt init Testnet - ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. + - **`tokenAddress`** - the address of the IERC-20 token on the target chain that has been transferred to this contract. If `tokenHomeChain` equals the target chain, this will be the same as `tokenHomeAddress`; otherwise, it will be the Wormhole-wrapped version of the token sent -### Set Mint Authority + - **`amount`** - the token amount sent to you with the same units as the original token. Since `TokenBridge` only sends with eight decimals of precision, if your token has 18 decimals, this will be the "amount" you sent, rounded down to the nearest multiple of 10^10 -If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. + - **`amountNormalized`** - the amount of token divided by (1 if decimals ≤ 8, else 10^(decimals - 8)) -If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). +You can find the complete code for the `CrossChainReceiver.sol` contract below: -Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. +??? code "CrossChainReceiver.sol" -Follow these steps to set the mint authority using the NTT CLI: + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +contract CrossChainReceiver is TokenReceiver { + // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract -2. **Derive the token authority** - generate the PDA, which will manage token minting + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - ```bash - ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR - ``` + // Function to receive the cross-chain payload and tokens with emitter validation + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + require(receivedTokens.length == 1, "Expected 1 token transfer"); -3. **Set SPL token mint authority** - delegate minting control to the derived PDA + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); - ```bash - spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} ``` -## Deploy and Configure NTT +## Deploy the Contracts -After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: +Now that you've written the `CrossChainSender` and `CrossChainReceiver` contracts, it's time to deploy them to your chosen networks. -1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: +1. **Set up deployment configuration** - before deploying, you must configure the networks and the deployment environment. This information is stored in a configuration file - === "Burn-and-Mint" + 1. Create a directory named deploy-config in the root of your project: ```bash - ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + mkdir deploy-config ``` - === "Hub-and-Spoke" + 2. Create a `config.json` file in the `deploy-config` directory: ```bash - ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + touch deploy-config/config.json ``` - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + 3. Open the `config.json` file and add the following configuration: -2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: + ```json + { + "chains": [ + { + "description": "Avalanche testnet fuji", + "chainId": 6, + "rpc": "https://api.avax-test.network/ext/bc/C/rpc", + "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", + "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", + "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" + }, + { + "description": "Celo Testnet", + "chainId": 14, + "rpc": "https://alfajores-forno.celo-testnet.org", + "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", + "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", + "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" + } + ] +} + ``` - ```bash - ntt status - ``` + This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. - If needed, sync your local configuration with the on-chain state: + For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. - ```bash - ntt pull - ``` + !!! note + You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. -3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. + 4. Create a `contracts.json` file in the `deploy-config` directory: - Open your `deployment.json` file and adjust the values based on your use case: + ```bash + echo '{}' > deploy-config/contracts.json + ``` - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - }, - "outbound": { - "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia - } - ``` + This file can be left blank initially. It will be automatically updated with the deployed contract addresses after a successful deployment -4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees +2. **Set up your Node.js environment** - you'll need to set up your Node.js environment to run the deployment script - ```bash - ntt push --payer INSERT_YOUR_KEYPAIR_JSON - ``` + 1. Initialize a Node.js project: -### Troubleshoot Deployment Issues + ```bash + npm init -y + ``` -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. - -## Where to Go Next - -
- -- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** - - --- - - After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - -- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** + 2. Install the necessary dependencies: - --- + ```bash + npm install ethers dotenv readline-sync @types/readline-sync + ``` - Follow the NTT Post Deployment Guide for integration examples and testing instructions. + These dependencies are required for the deployment script to work properly. - [:custom-arrow: Test Your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/){target=\_blank} +3. **Compile your smart contracts** - compile your smart contracts using Foundry. This ensures that your contracts are up-to-date and ready for deployment -- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** + - Run the following command to compile your contracts: - --- + ```bash + forge build + ``` - Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. + This will generate the necessary ABI and bytecode files in a directory named `/out`. - [:custom-arrow: Use Connect to Integrate NTT](/docs/build/transfers/connect/){target=\_blank} + The expected output should be similar to this: +
+forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! +
---- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ ---- BEGIN CONTENT --- ---- -title: Deploy Native Token Transfers with Launchpad -description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -categories: NTT, Transfer ---- +4. **Write the deployment script** - you’ll need a script to automate the deployment of your contracts. Let’s create the deployment script -# Deploy Native Token Transfers with Launchpad + 1. Create a new file named `deploy.ts` in the `/script` directory: -## Introduction + ```bash + touch script/deploy.ts + ``` -The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. + 2. Open the file and load imports and configuration: -Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. + ```typescript + import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -The Launchpad automates deployment, reducing complexity and saving time. +dotenv.config(); + ``` -This guide covers: + Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal. + + 3. Define interfaces to use for chain configuration and contract deployment: - - Launching a new cross-chain token - - Expanding an existing token for NTT - - Managing tokens via the dashboard and settings + ```typescript + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -## Prerequisites +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} + ``` - - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) - - Minimum ETH (or equivalent) for gas fees per deployment + These interfaces define the structure of the chain configuration and the contract deployment details. -## Supported Blockchains + 4. Load and select the chains for deployment: -The NTT Launchpad currently supports deployments on the following mainnet chains: + ```typescript + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} - - Ethereum - - Arbitrum One - - Base - - Berachain - - Blast - - BNB Smart Chain - - Ink - - Optimism Mainnet - - Polygon +function selectChain( + chains: ChainConfig[], + role: 'source' | 'target' +): ChainConfig { + console.log(`\nSelect the ${role.toUpperCase()} chain:`); + chains.forEach((chain, index) => { + console.log(`${index + 1}: ${chain.description}`); + }); -## Choose Your Path + const chainIndex = + readlineSync.questionInt( + `\nEnter the number for the ${role.toUpperCase()} chain: ` + ) - 1; + return chains[chainIndex]; +} + ``` -Once ready, choose an option to proceed: + The `loadConfig` function reads the chain configuration from the `config.json` file, and the `selectChain` function allows the user to choose the source and target chains for deployment interactively. The user is prompted in the terminal to select which chains to use, making the process interactive and user-friendly. - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + 5. Define the main function for deployment and load the chain configuration: -## Launch a Cross-Chain Token + ```typescript + const chains = loadConfig(); -Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: + const sourceChain = selectChain(chains, 'source'); + const targetChain = selectChain(chains, 'target'); + ``` -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + - The `main` function is the entry point for the deployment script + - We then call the `loadConfig` function we previously defined to load the chain configuration from the `config.json` file - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + 6. Set up provider and wallet: -2. Select **Launch a Cross-Chain Token** + ```typescript + const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); + ``` + + The scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction on the source chain. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) + 7. Read the compiled contracts: -3. Set the token details: - 1. Select the **home network** from the dropdown menu - 2. Enter the **name** for the token - 3. Enter the **symbol** of the token - 4. Provide the **initial supply** - 5. To the token details, click **Next** + ```typescript + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) + - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract + - The file is in the `../out/` directory, which contains the ABI (Application Binary Interface) and bytecode generated during contract compilation + - It uses the `fs.readFileSync` function to read the file and `JSON.parse` to convert the file contents (in JSON format) into a JavaScript object -4. Select the deployment chains: - 1. The home network where your token will be deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** + 8. Extract the contract ABI and bytecode: - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) + ```typescript + const bytecode = senderJson.bytecode; + ``` -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + - **ABI (Application Binary Interface)** - defines the structure of the contract’s functions, events, and data types, allowing the front end to interact with the contract on the blockchain + - **Bytecode** - this is the compiled machine code that will be deployed to the blockchain to create the contract - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + 9. Create the Contract Factory: -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + ```typescript + abi, + bytecode, + wallet + ); + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + - **`ethers.ContractFactory`** - creates a new contract factory using the ABI, bytecode, and a wallet (representing the signer). The contract factory is responsible for deploying instances of the contract to the blockchain + - This is a crucial step for deploying the contract since the factory will create and deploy the `CrossChainSender` contract -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + 10. Deploy the `CrossChainSender` and `CrossChainReceiver` contracts: -8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. + === "`CrossChainSender`" + ```typescript + const senderContract = await CrossChainSenderFactory.deploy( + sourceChain.wormholeRelayer, + sourceChain.tokenBridge, + sourceChain.wormhole + ); + await senderContract.waitForDeployment(); + ``` -## Expand Your Existing Token + === "`CrossChainReceiver`" + ```typescript + process.env.PRIVATE_KEY!, + targetProvider + ); + const receiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainReceiver.sol/CrossChainReceiver.json' + ), + 'utf8' + ) + ); + const CrossChainReceiverFactory = new ethers.ContractFactory( + receiverJson.abi, + receiverJson.bytecode, + targetWallet + ); -Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: + const receiverContract = await CrossChainReceiverFactory.deploy( + targetChain.wormholeRelayer, + targetChain.tokenBridge, + targetChain.wormhole + ); + await receiverContract.waitForDeployment(); + ``` -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + Both functions deploy the respective contracts to the selected chains. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + For the `CrossChainReceiver` contract: -2. Select **Expand Your Existing Token** + - It defines the wallet related to the target chain + - The logic reads the compiled ABI and bytecode from the JSON file generated during compilation + - It creates a new contract factory using the ABI, bytecode, and wallet + - It deploys the contract to the selected chain passing in the Wormhole Relayer, `TokenBridge`, and Wormhole addresses - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) + 11. Save the deployed contract addresses: -3. Enter the token details: - 1. Choose the home network where your token is already deployed (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** + === "`senderAddress`" + ```typescript + console.log( + `CrossChainSender on ${sourceChain.description}: ${senderAddress}` + ); + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) + === "`receiverAddress`" + ```typescript + console.log( + `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` + ); + ``` -4. Select the chains to deploy your token to: - 1. The home network where your token is already deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 1. Click **Next** + You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + 12. Register the `CrossChainSender` address on the target chain: -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + ```typescript + receiverAddress, + receiverJson.abi, + targetWallet + ); - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + const tx = await CrossChainReceiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) + ); -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + await tx.wait(); + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + After you deploy the `CrossChainReceiver` contract on the target network, the sender contract address from the source chain needs to be registered. This ensures that only messages from the registered `CrossChainSender` contract are processed. -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `CrossChainReceiver` contract. -8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details + 13. Save the deployment details: -## Explore the Launchpad Dashboard + ???- example "Save Deployment Details Example" + ```typescript + __dirname, + '../deploy-config/contracts.json' + ); + let deployedContracts: DeployedContracts = {}; -To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. + if (fs.existsSync(deployedContractsPath)) { + deployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); + } + + // Update the contracts.json file: + // If a contract already exists on a chain, update its address; otherwise, add a new entry. + if (!deployedContracts[sourceChain.chainId]) { + deployedContracts[sourceChain.chainId] = { + networkName: sourceChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[sourceChain.chainId].CrossChainSender = + senderAddress.toString(); + deployedContracts[sourceChain.chainId].deployedAt = + new Date().toISOString(); + + if (!deployedContracts[targetChain.chainId]) { + deployedContracts[targetChain.chainId] = { + networkName: targetChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[targetChain.chainId].CrossChainReceiver = + receiverAddress.toString(); + deployedContracts[targetChain.chainId].deployedAt = + new Date().toISOString(); -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) + // Save the updated contracts.json file + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); + ``` + + Add your desired logic to save the deployed contract addresses in a JSON file (or another format). This will be important later when transferring tokens, as you'll need these addresses to interact with the deployed contracts. -The dashboard provides a high-level view of your token across all deployed chains, including: + 14. Handle errors and finalize the script: - - Token addresses for each chain - - Supply distribution visualization - - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) + ```typescript + if (error.code === 'INSUFFICIENT_FUNDS') { + console.error( + 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' + ); + } else { + console.error('An unexpected error occurred:', error.message); + } + process.exit(1); + } +} -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) +main().catch((error) => { + console.error(error); + process.exit(1); +}); + ``` -## Settings + The try-catch block wraps the deployment logic to catch any errors that may occur. -The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. + - If the error is due to insufficient funds, it logs a clear message about needing more gas fees + - For any other errors, it logs the specific error message to help with debugging -### Chain Management + The `process.exit(1)` ensures that the script exits with a failure status code if any error occurs. -Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. + You can find the full code for the `deploy.ts` file below: -From this section, you can also: + ??? code "deploy.ts" - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain + ```solidity + import { BytesLike, ethers } from 'ethers'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) +dotenv.config(); -### Role Management +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers +function loadConfig(): ChainConfig[] { + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) +function selectChain( + chains: ChainConfig[], + role: 'source' | 'target' +): ChainConfig { + console.log(`\nSelect the ${role.toUpperCase()} chain:`); + chains.forEach((chain, index) => { + console.log(`${index + 1}: ${chain.description}`); + }); -### Security Threshold + const chainIndex = + readlineSync.questionInt( + `\nEnter the number for the ${role.toUpperCase()} chain: ` + ) - 1; + return chains[chainIndex]; +} -Determine and update how transceivers interact with the token. [Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +async function main() { + const chains = loadConfig(); -A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. + const sourceChain = selectChain(chains, 'source'); + const targetChain = selectChain(chains, 'target'); - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) + const senderJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); -### Peer Chains Limits + const abi = senderJson.abi; + const bytecode = senderJson.bytecode; -Define the transfer restrictions for each connected network. You can adjust: + const CrossChainSenderFactory = new ethers.ContractFactory( + abi, + bytecode, + wallet + ); - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + try { + const senderContract = await CrossChainSenderFactory.deploy( + sourceChain.wormholeRelayer, + sourceChain.tokenBridge, + sourceChain.wormhole + ); + await senderContract.waitForDeployment(); -Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. + // Safely access the deployed contract's address + const senderAddress = (senderContract as ethers.Contract).target; + console.log( + `CrossChainSender on ${sourceChain.description}: ${senderAddress}` + ); -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) ---- END CONTENT --- + const targetWallet = new ethers.Wallet( + process.env.PRIVATE_KEY!, + targetProvider + ); + const receiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainReceiver.sol/CrossChainReceiver.json' + ), + 'utf8' + ) + ); + const CrossChainReceiverFactory = new ethers.ContractFactory( + receiverJson.abi, + receiverJson.bytecode, + targetWallet + ); -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) - Deployment -description: This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. -categories: NTT, Transfer ---- + const receiverContract = await CrossChainReceiverFactory.deploy( + targetChain.wormholeRelayer, + targetChain.tokenBridge, + targetChain.wormhole + ); + await receiverContract.waitForDeployment(); -# Deploy Native Token Transfers (NTT) + // Safely access the deployed contract's address + const receiverAddress = (receiverContract as ethers.Contract).target; + console.log( + `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` + ); -## Get Started + // Register the sender contract in the receiver contract + console.log( + `Registering CrossChainSender (${senderAddress}) as a valid sender in CrossChainReceiver (${receiverAddress})...` + ); -This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. + const CrossChainReceiverContract = new ethers.Contract( + receiverAddress, + receiverJson.abi, + targetWallet + ); -
+ const tx = await CrossChainReceiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) + ); -- :octicons-download-16:{ .lg .middle } **Installation** + await tx.wait(); + console.log( + `CrossChainSender registered as a valid sender on ${targetChain.description}` + ); - --- + // Load existing deployed contract addresses from contracts.json + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + let deployedContracts: DeployedContracts = {}; - Prerequisites and commands for installing the NTT CLI and working with the NTT framework. + if (fs.existsSync(deployedContractsPath)) { + deployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); + } - [:custom-arrow: Install the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/) + // Update the contracts.json file: + // If a contract already exists on a chain, update its address; otherwise, add a new entry. + if (!deployedContracts[sourceChain.chainId]) { + deployedContracts[sourceChain.chainId] = { + networkName: sourceChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[sourceChain.chainId].CrossChainSender = + senderAddress.toString(); + deployedContracts[sourceChain.chainId].deployedAt = + new Date().toISOString(); -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** + if (!deployedContracts[targetChain.chainId]) { + deployedContracts[targetChain.chainId] = { + networkName: targetChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[targetChain.chainId].CrossChainReceiver = + receiverAddress.toString(); + deployedContracts[targetChain.chainId].deployedAt = + new Date().toISOString(); - --- + // Save the updated contracts.json file + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); + } catch (error: any) { + if (error.code === 'INSUFFICIENT_FUNDS') { + console.error( + 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' + ); + } else { + console.error('An unexpected error occurred:', error.message); + } + process.exit(1); + } +} - Find information on preparing for NTT deployment to EVM, including an example NTT token repository. +main().catch((error) => { + console.error(error); + process.exit(1); +}); + ``` - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-evm/) +5. **Add your private key** - you'll need to provide your private key. It allows your deployment script to sign the transactions that deploy the smart contracts to the blockchain. Without it, the script won't be able to interact with the blockchain on your behalf -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains via Launchpad** + Create a `.env` file in the root of the project and add your private key: - --- + ```bash + touch .env + ``` - Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. + Inside `.env`, add your private key in the following format: - [:custom-arrow: Deploy via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) + ```env + PRIVATE_KEY=INSERT_PRIVATE_KEY + ``` + +6. **Run the deployment script** -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** + 1. Open a terminal and run the following command: - --- + ```bash + npx ts-node script/deploy.ts + ``` - Your guide to NTT deployment to Solana, including setup, token compatibility, mint/burn modes, and CLI usage. + This will execute the deployment script, deploying both contracts to the selected chains. - [:custom-arrow: Deploy token and NTT contracts](/docs/products/native-token-transfers/guides/deploy-to-solana/) + 2. Check the deployment output: -- :octicons-search-16:{ .lg .middle } **Post Deployment** + - You will see the deployed contract addresses printed in the terminal if successful. The `contracts.json` file will be updated with these addresses + - If you encounter an error, the script will provide feedback, such as insufficient funds for gas - --- +If you followed the logic provided in the full code above, your terminal output should look something like this: - Learn how to best monitor and maintain your NTT deployment to get the most out of your Wormhole integration while providing security for users. +
+npx ts-node deploy.ts + > cross-chain-token-transfer@1.0.0 deploy + > npx ts-node script/deploy.ts + Select the SOURCE chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the SOURCE chain: 1 + + Select the TARGET chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the TARGET chain: 2 + CrossChainSender Avalanche testnet fuji: 0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3 + CrossChainReceiver Celo Testnet: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 + + Registering CrossChainSender (0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3) as a valid sender in CrossChainReceiver (0xD720BFF42a0960cfF1118454A907a44dB358f2b1)... + + CrossChainSender registered as a valid sender on Celo Testnet + +
- [:custom-arrow: Explore next steps](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) -- :octicons-alert-16:{ .lg .middle } **Troubleshooting** +## Transfer Tokens Across Chains - --- +### Quick Recap - Explore solutions and detailed guidance in our troubleshooting guide to resolve issues with NTT deployment. +Up to this point, you've set up a new Solidity project using Foundry, developed two key contracts (`CrossChainSender` and `CrossChainReceiver`), and created a deployment script to deploy these contracts to different blockchain networks. The deployment script also saves the new contract addresses for easy reference. With everything in place, it's time to transfer tokens using the deployed contracts. - [:custom-arrow: Get help](/docs/products/native-token-transfers/troubleshooting/) +In this step, you'll write a script to transfer tokens across chains using the `CrossChainSender` and `CrossChainReceiver` contracts you deployed earlier. This script will interact with the contracts and facilitate the cross-chain token transfer. -
---- END CONTENT --- +### Transfer Script -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- +1. **Set up the transfer script** -# Install the Native Token Transfers CLI + 1. Create a new file named `transfer.ts` in the `/script` directory: -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. + ```bash + touch script/transfer.ts + ``` -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. + 2. Open the file. Start with the necessary imports, interfaces and configurations: -
+ ```typescript + import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -## Install NTT CLI +dotenv.config(); -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} + ``` -Follow these steps to install the NTT CLI: + These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input. -1. Run the installation command in your terminal: + 3. Load configuration and contracts: - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` -2. Verify the NTT CLI is installed: + ```typescript + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} - ```bash - ntt --version - ``` +function loadDeployedContracts(): DeployedContracts { + const contractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + if ( + !fs.existsSync(contractsPath) || + fs.readFileSync(contractsPath, 'utf8').trim() === '' + ) { + console.error( + 'No contracts found. Please deploy contracts first before transferring tokens.' + ); + process.exit(1); + } + return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); +} + ``` -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI + These functions load the network and contract details that were saved during deployment. -## Update NTT CLI + 4. Allow users to select source and target chains: -To update an existing NTT CLI installation, run the following command in your terminal: + Refer to the deployed contracts and create logic as desired. In our example, we made this process interactive, allowing users to select the source and target chains from all the historically deployed contracts. This interactive approach helps ensure the correct chains are selected for the token transfer. -```bash -ntt update -``` + ```typescript + chainId: number; + networkName: string; +} { + const sourceOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainSender + ); -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. + if (sourceOptions.length === 0) { + console.error('No source chains available with CrossChainSender deployed.'); + process.exit(1); + } -For local development, you can update your CLI version from a specific branch or install from a local path. + console.log('\nSelect the source chain:'); + sourceOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); -To install from a specific branch, run: + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; + return { + chainId: Number(sourceOptions[selectedIndex][0]), + networkName: sourceOptions[selectedIndex][1].networkName, + }; +} -```bash -ntt update --branch foo -``` +function selectTargetChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const targetOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainReceiver + ); -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` + if (targetOptions.length === 0) { + console.error( + 'No target chains available with CrossChainReceiver deployed.' + ); + process.exit(1); + } -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. + console.log('\nSelect the target chain:'); + targetOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); -## Where to Go Next + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; + return { + chainId: Number(targetOptions[selectedIndex][0]), + networkName: targetOptions[selectedIndex][1].networkName, + }; +} + ``` -
+2. **Implement the token transfer logic** + 1. Start the `main` function: + + ```typescript + const chains = loadConfig(); + const deployedContracts = loadDeployedContracts(); -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** + // Select the source chain (only show chains with CrossChainSender deployed) + const { chainId: sourceChainId, networkName: sourceNetworkName } = + selectSourceChain(deployedContracts); + const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; - --- + // Select the target chain (only show chains with CrossChainReceiver deployed) + const { chainId: targetChainId, networkName: targetNetworkName } = + selectTargetChain(deployedContracts); + const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. + // Set up providers and wallets + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) + // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** + const abi = CrossChainSenderArtifact.abi; - --- + // Create the contract instance using the full ABI + const CrossChainSender = new ethers.Contract( + deployedContracts[sourceChainId].CrossChainSender!, + abi, + wallet + ); + ``` + + The `main` function is where the token transfer logic will reside. It loads the chain and contract details, sets up the wallet and provider, and loads the `CrossChainSender` contract. - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. + 2. Ask the user for token transfer details: - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) + You'll now ask the user for the token contract address, the recipient address on the target chain, and the amount of tokens to transfer. -
---- END CONTENT --- + ```typescript + 'Enter the token contract address: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on the target chain: ' + ); -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -categories: NTT, Transfer ---- + // Get the token contract + const tokenContractDecimals = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + ], + wallet + ); -# Native Token Transfers Post Deployment + // Fetch the token decimals + const decimals = await tokenContractDecimals.decimals(); -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): + // Get the amount from the user, then parse it according to the token's decimals + const amount = ethers.parseUnits( + readlineSync.question('Enter the amount of tokens to transfer: '), + decimals + ); + ``` -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/build/transfers/connect/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment + This section of the script prompts the user for the token contract address and the recipient's address, fetches the token's decimal value, and parses the amount accordingly. -## Manual Relaying for Solana Transfers + 3. Initiate the transfer: -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. + Finally, initiate the cross-chain transfer and log the details. -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. + ```typescript + // Approve the CrossChainSender contract to transfer tokens on behalf of the user + const tokenContract = new ethers.Contract( + tokenAddress, + ['function approve(address spender, uint256 amount) public returns (bool)'], + wallet + ); -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. + const approveTx = await tokenContract.approve( + deployedContracts[sourceChainId].CrossChainSender!, + amount + ); + await approveTx.wait(); + console.log(`Approved tokens for cross-chain transfer.`); -## Where to Go Next + // Initiate the cross-chain transfer + const transferTx = await CrossChainSender.sendCrossChainDeposit( + targetChainId, + deployedContracts[targetChainId].CrossChainReceiver!, + recipientAddress, + amount, + tokenAddress, + { value: cost } // Attach the necessary fee for cross-chain transfer + ); + await transferTx.wait(); + console.log( + `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` + ); +} + ``` -
+ This part of the script first approves the token transfer, then initiates the cross-chain transfer using the `CrossChainSender` contract, and finally logs the transaction hash for the user to track. -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** + 4. Finalize the script: - --- + ```typescript + console.error(error); + process.exit(1); +}); + ``` - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + This section finalizes the script by calling the `main` function and handling any errors that may occur during the token transfer process. - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) +You can find the full code for the `transfer.ts` file below: -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** +??? code "transfer.ts" - --- + ```solidity + import { ethers } from 'ethers'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. +dotenv.config(); - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -
---- END CONTENT --- +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ ---- BEGIN CONTENT --- ---- -title: Troubleshooting NTT Deployment -description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. -categories: NTT, Transfer ---- +function loadConfig(): ChainConfig[] { + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} -# Troubleshooting NTT Deployment +function loadDeployedContracts(): DeployedContracts { + const contractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + if ( + !fs.existsSync(contractsPath) || + fs.readFileSync(contractsPath, 'utf8').trim() === '' + ) { + console.error( + 'No contracts found. Please deploy contracts first before transferring tokens.' + ); + process.exit(1); + } + return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); +} -If you encounter issues during the NTT deployment process, check the following common points: +function selectSourceChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const sourceOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainSender + ); -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain -- **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} -- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file + if (sourceOptions.length === 0) { + console.error('No source chains available with CrossChainSender deployed.'); + process.exit(1); + } - ???- interface "Dockerfile" + console.log('\nSelect the source chain:'); + sourceOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - ```Dockerfile - FROM ubuntu:20.04 - # Set environment variables to prevent interactive prompts during installation - ENV DEBIAN_FRONTEND=noninteractive + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; + return { + chainId: Number(sourceOptions[selectedIndex][0]), + networkName: sourceOptions[selectedIndex][1].networkName, + }; +} - # Update and install necessary dependencies - RUN apt-get update && apt-get install -y \ - curl \ - wget \ - git \ - build-essential \ - libssl-dev \ - libudev-dev \ - pkg-config \ - python3 \ - python3-pip \ - software-properties-common \ - ca-certificates \ - unzip \ - clang \ - cmake \ - protobuf-compiler \ - && apt-get clean && rm -rf /var/lib/apt/lists/* +function selectTargetChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const targetOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainReceiver + ); - # Install Rust - RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - ENV PATH="/root/.cargo/bin:$PATH" + if (targetOptions.length === 0) { + console.error( + 'No target chains available with CrossChainReceiver deployed.' + ); + process.exit(1); + } - # Install Solana CLI ({{ntt.solana_cli_version}}) - RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" - ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" + console.log('\nSelect the target chain:'); + targetOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - # Install Anchor using avm - RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ - && avm install 0.29.0 \ - && avm use 0.29.0 - ENV PATH="/root/.avm/bin:$PATH" + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; + return { + chainId: Number(targetOptions[selectedIndex][0]), + networkName: targetOptions[selectedIndex][1].networkName, + }; +} +async function main() { + const chains = loadConfig(); + const deployedContracts = loadDeployedContracts(); - ENV NVM_DIR=/root/.nvm - RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install 22 \ - && nvm use 22 \ - && nvm alias default 22 - ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" + // Select the source chain (only show chains with CrossChainSender deployed) + const { chainId: sourceChainId, networkName: sourceNetworkName } = + selectSourceChain(deployedContracts); + const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; - # Install Bun - RUN curl -fsSL https://bun.sh/install | bash - ENV PATH="/root/.bun/bin:$PATH" + // Select the target chain (only show chains with CrossChainReceiver deployed) + const { chainId: targetChainId, networkName: targetNetworkName } = + selectTargetChain(deployedContracts); + const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; - # Install Foundry - RUN curl -L https://foundry.paradigm.xyz | bash - ENV PATH="/root/.foundry/bin:${PATH}" - RUN /bin/bash -c "source /root/.bashrc && foundryup" + // Set up providers and wallets + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); - # Install Wormhole NTT CLI - RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); - # Add a default working directory - WORKDIR /app + const abi = CrossChainSenderArtifact.abi; - # Expose port for development if needed - EXPOSE 8899 + // Create the contract instance using the full ABI + const CrossChainSender = new ethers.Contract( + deployedContracts[sourceChainId].CrossChainSender!, + abi, + wallet + ); - # Entry point for the container - CMD ["bash"] - ``` + // Display the selected chains + console.log( + `\nInitiating transfer from ${sourceNetworkName} to ${targetNetworkName}.` + ); - ???- interface "docker-compose.yml" - ```yml - services: - portal-ntt: - build: - context: . - dockerfile: Dockerfile - platform: linux/amd64 - volumes: - - ./src:/app - working_dir: /app - tty: true - ``` ---- END CONTENT --- + // Ask the user for token transfer details + const tokenAddress = readlineSync.question( + 'Enter the token contract address: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on the target chain: ' + ); -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers FAQs -description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -categories: NTT, Transfer ---- + // Get the token contract + const tokenContractDecimals = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + ], + wallet + ); -# Wormhole NTT FAQs + // Fetch the token decimals + const decimals = await tokenContractDecimals.decimals(); -## Do you have an example of how cross-chain lending can be implemented using Wormhole? + // Get the amount from the user, then parse it according to the token's decimals + const amount = ethers.parseUnits( + readlineSync.question('Enter the amount of tokens to transfer: '), + decimals + ); -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. + // Calculate the cross-chain transfer cost + const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId); -Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/learn/transfers/native-token-transfers/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. + // Approve the CrossChainSender contract to transfer tokens on behalf of the user + const tokenContract = new ethers.Contract( + tokenAddress, + ['function approve(address spender, uint256 amount) public returns (bool)'], + wallet + ); -## What causes the "No protocols registered for Evm" error in Wormhole SDK? + const approveTx = await tokenContract.approve( + deployedContracts[sourceChainId].CrossChainSender!, + amount + ); + await approveTx.wait(); + console.log(`Approved tokens for cross-chain transfer.`); -This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. + // Initiate the cross-chain transfer + const transferTx = await CrossChainSender.sendCrossChainDeposit( + targetChainId, + deployedContracts[targetChainId].CrossChainReceiver!, + recipientAddress, + amount, + tokenAddress, + { value: cost } // Attach the necessary fee for cross-chain transfer + ); + await transferTx.wait(); + console.log( + `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` + ); +} -To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: +main().catch((error) => { + console.error(error); + process.exit(1); +}); + ``` -```rust -import '@wormhole-foundation/sdk-evm-ntt'; -``` +### Transfer Tokens -By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. +Now that your transfer script is ready, it’s time to execute it and perform a cross-chain token transfer. -## How can I transfer ownership of NTT to a multisig? +1. **Run the transfer script** -Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. + Open your terminal and run the transfer script: -1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) -2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer -3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) + ```bash + npx ts-node script/transfer.ts + ``` -For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. + This command will start the script, prompting you to select the source and target chains, input the token address, recipient address, and the amount of tokens to transfer. -## How can I specify a custom RPC for NTT? +2. **Follow the prompts** - the script will guide you through selecting the source and target chains and entering the necessary details for the token transfer. Once you provide all the required information, the script will initiate the token transfer -To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. +3. **Verify the transaction** - after running the script, you should see a confirmation message with the transaction hash. You can use this transaction hash to check the transfer status on the respective blockchain explorers -Below’s an example of how the `overrides.json` file should be structured: +You can verify the transaction on the [Wormhole Explorer](https://wormholescan.io/){target=\_balnk} using the link provided in the terminal output. This explorer also offers the option to add the transferred token to your MetaMask wallet automatically. -???- code "`overrides.json`" - ```json - { - "chains": { - "Bsc": { - "rpc": "http://127.0.0.1:8545" - }, - "Sepolia": { - "rpc": "http://127.0.0.1:8546" - }, - "Solana": { - "rpc": "http://127.0.0.1:8899" - } - } - } - ``` +If you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this: -## How can I redeem tokens if NTT rate limits block them on the target chain? +
+npx ts-node transfer.ts + > cross-chain-token-transfer@1.0.0 transfer + > npx ts-node script/transfer.ts + + Select the source chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the SOURCE chain: 1 + + Select the target chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the TARGET chain: 2 + + Initiating transfer from Avalanche testnet fuji to Celo Testnet + Enter the token contract address: 0x5425890298aed601595a70ab815c96711a31bc65 + Enter the recipient address on the target chain: INSERT_YOUR_WALLET_ADDRESS + Enter the amount of tokens to transfer: 2 + Approved tokens for cross-chain transfer. + Transfer initiated from Avalanche testnet fuji to Celo Testnet. Transaction Hash: 0x4a923975d955c1f226a1c2f61a1a0fa1ab1a9e229dc29ceaeadf8ef40acd071f + +
-If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. +!!! note + In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. We sent two units of USDC Testnet tokens using the token contract address `0x5425890298aed601595a70ab815c96711a31bc65`. You can replace these details with those relevant to your project or use the same for testing purposes. -To resolve this: +## Resources -1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed -2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in the [Cross-Chain Token Transfers GitHub repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank}. The repository includes all the scripts, contracts, and configurations needed to deploy and transfer tokens across chains using the Wormhole protocol. -In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. +## Conclusion -## What are the challenges of deploying NTT to non-EVM chains? +Congratulations! You've successfully built and deployed a cross-chain token transfer system using Solidity and the Wormhole protocol. You've learned how to: -NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. + - Set up a new Solidity project using Foundry + - Develop smart contracts to send and receive tokens across chains + - Write deployment scripts to manage and deploy contracts on different networks +--- END CONTENT --- -## Does the NTT manager function as an escrow account for a hub chain? +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ +--- BEGIN CONTENT --- +--- +title: Replace Outdated Signatures in VAAs +description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. +--- -Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. +# Replace Outdated Signatures in VAAs -## Which functions or events does Connect rely on for NTT integration? +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} -Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: +## Introduction -- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain -- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion +Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. -These functions ensure Connect can handle token transfers and manage chain-rate limits. +However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. -## How does the relayer contract determine which transceiver to call? +Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. -The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. +In this tutorial, you'll build a script from scratch to: -## How do I create a verifier or transceiver? +- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} +- Validate its signatures against the latest Guardian set +- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} +- Output a valid VAA ready for submission -To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. +By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. -For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. +## Prerequisites -## Can I use Hetzner for the NTT deployment? +Before you begin, ensure you have the following: -No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally -## How can I transfer tokens with NTT with an additional payload? +## Project Setup -You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. +In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. -- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message -- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message +1. **Create the project** - set up the directory and navigate into it -!!!Important - You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. + ```bash + mkdir wormhole-scan-api-demo + cd wormhole-scan-api-demo + ``` -## Why use NTT over xERC20? +2. **Initialize a Node.js project** - generate a `package.json` file -Shortcomings of xERC20: + ```bash + npm init -y + ``` -- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach -- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies -- **No access control** - there are no built-in access controls for managing token transfers securely -- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security -- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups +3. **Set up TypeScript** - create a `tsconfig.json` file -While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. + ```bash + touch tsconfig.json + ``` -## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? + Then, add the following configuration: -To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. + ```json title="tsconfig.json" + { + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} + ``` -## Is there a way to use NTT tokens with chains that don't currently support NTT? +4. **Install dependencies** - add the required packages -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: + ```bash + npm install @wormhole-foundation/sdk axios web3 tsx @types/node + ``` -- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) -- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism -- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT + - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions + - `axios` - makes HTTP requests to the Wormholescan API + - `web3` - interacts with Ethereum transactions and contracts + - `tsx` - executes TypeScript files without compilation + - `@types/node` - provides Node.js type definitions -This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. ---- END CONTENT --- +5. **Create the project structure** - set up the required directories and files -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- + ```bash + mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts + mkdir -p src/helpers && touch src/helpers/vaaHelper.ts + mkdir -p src/scripts && touch scripts/replaceSignatures.ts + ``` -# Native Token Transfers + - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures + - **`src/helpers/*`** - contains utility functions + - **`src/scripts/*`** - contains scripts for fetching and replacing signatures -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. +6. **Set variables** - define key constants in `src/config/constants.ts` -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. + ```bash title="src/config/constants.ts" + export const RPC = 'https://ethereum-rpc.publicnode.com'; -## Quickstart +export const ETH_CORE = + '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase(); -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +export const WORMHOLESCAN_API = 'https://api.wormholescan.io/v1'; -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: +export const LOG_MESSAGE_PUBLISHED_TOPIC = + '0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2'; -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] +export const TXS = [ + '0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367', + '0x3c989a6bb40dcd4719453fbe7bbac420f23962c900ae75793124fc9cc614368c', +]; + ``` -## Deploy NTTs with Launchpad + - **`RPC`** - endpoint for interacting with an Ethereum RPC node + - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs + - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets + - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts + - **`TXS`** - list of example transaction hashes that will be used for testing -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. +7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. + ```typescript title="src/config/layouts.ts" + export const PARSE_AND_VERIFY_VM_ABI = { + inputs: [{ internalType: 'bytes', name: 'encodedVM', type: 'bytes' }], + name: 'parseAndVerifyVM', + outputs: [ + { + components: [ + { internalType: 'uint8', name: 'version', type: 'uint8' }, + { internalType: 'uint32', name: 'timestamp', type: 'uint32' }, + { internalType: 'uint32', name: 'nonce', type: 'uint32' }, + { internalType: 'uint16', name: 'emitterChainId', type: 'uint16' }, + { internalType: 'bytes32', name: 'emitterAddress', type: 'bytes32' }, + { internalType: 'uint64', name: 'sequence', type: 'uint64' }, + { internalType: 'uint8', name: 'consistencyLevel', type: 'uint8' }, + { internalType: 'bytes', name: 'payload', type: 'bytes' }, + { internalType: 'uint32', name: 'guardianSetIndex', type: 'uint32' }, + { + components: [ + { internalType: 'bytes32', name: 'r', type: 'bytes32' }, + { internalType: 'bytes32', name: 's', type: 'bytes32' }, + { internalType: 'uint8', name: 'v', type: 'uint8' }, + { internalType: 'uint8', name: 'guardianIndex', type: 'uint8' }, + ], + internalType: 'struct Structs.Signature[]', + name: 'signatures', + type: 'tuple[]', + }, + { internalType: 'bytes32', name: 'hash', type: 'bytes32' }, + ], + internalType: 'struct Structs.VM', + name: 'vm', + type: 'tuple', + }, + { internalType: 'bool', name: 'valid', type: 'bool' }, + { internalType: 'string', name: 'reason', type: 'string' }, + ], + stateMutability: 'view', + type: 'function', +}; + ``` -## Additional Resources +## Create VAA Handling Functions -
+In this section, we'll create a series of helper functions in the `src/helpers/vaaHelper.ts` file that will retrieve and verify VAAs and fetch and replace outdated Guardian signatures to generate a correctly signed VAA. -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** +To get started, import the necessary dependencies: - --- +```typescript title="src/helpers/vaaHelper.ts" +import { eth } from 'web3'; +import { + deserialize, + serialize, + VAA, + Signature, +} from '@wormhole-foundation/sdk'; +import { + RPC, + ETH_CORE, + LOG_MESSAGE_PUBLISHED_TOPIC, + WORMHOLESCAN_API, +} from '../config/constants'; +import { PARSE_AND_VERIFY_VM_ABI } from '../config/layouts'; +``` - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. +### Fetch a VAA ID from a Transaction - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) +To retrieve a VAA, we first need to get its VAA ID from a transaction hash. This ID allows us to fetch the full VAA later. +The VAA ID is structured as follows: -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +```bash +chain/emitter/sequence +``` - --- + - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) + - `emitter` - the contract address that emitted the VAA + - `sequence` - a unique identifier for the event - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +We must assemble the ID correctly since this is the format the Wormholescan API expects when querying VAAs. - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +Follow the below steps to process the transaction logs and construct the VAA ID: -
---- END CONTENT --- +1. **Get the transaction receipt** - iterate over the array of transaction hashes and fetch the receipt to access its logs -Doc-Content: https://wormhole.com/docs/build/transfers/native-token-transfers/managers-transceivers/ ---- BEGIN CONTENT --- ---- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -categories: NTT, Transfer ---- +2. **Find the Wormhole event** - iterate over the transaction logs and check for events emitted by the Wormhole Core contract. Look specifically for `LogMessagePublished` events, which indicate a VAA was created -# Managers and Transceivers +3. **Extract the emitter and sequence number** - if a matching event is found, extract the emitter address from `log.topics[1]` and remove the `0x` prefix. Then, the sequence number from `log.data` is extracted, converting it from hex to an integer -## Managers +4. **Construct the VAA ID** - format the extracted data in `chain/emitter/sequence` format -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: +```typescript title="src/helpers/vaaHelper.ts" +const vaaIds: string[] = []; -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain + for (const tx of txHashes) { + try { + const result = ( + await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_getTransactionReceipt', + params: [tx], + }) + ).data.result; - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` + if (!result) + throw new Error(`Unable to fetch transaction receipt for ${tx}`); -- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer + for (const log of result.logs) { + if ( + log.address === ETH_CORE && + log.topics?.[0] === LOG_MESSAGE_PUBLISHED_TOPIC + ) { + const emitter = log.topics[1].substring(2); + const seq = BigInt(log.data.substring(0, 66)).toString(); + vaaIds.push(`2/${emitter}/${seq}`); + } + } + } catch (error) { + console.error(`Error processing ${tx}:`, error); + } + } - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` + return vaaIds; +} +``` -- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected +???- code "Try it out: VAA ID retrieval" + If you want to try out the function before moving forward, create a test file inside the `test` directory: - ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner - ``` + 1. **Create the directory and file** - add a script to call `fetchVaaId` and print the result -## Transceivers + ```bash + mkdir -p test + touch test/fetchVaaId.run.ts + ``` + 2. **Add the function call** -_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: + ```typescript title="test/fetchVaaId.run.ts" + import { fetchVaaId } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system +const testFetchVaaId = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager - ``` + if (vaaIds.length > 0) { + console.log(`Transaction: ${tx}`); + vaaIds.forEach((vaaId) => console.log(`VAA ID: ${vaaId}`)); + } else { + console.log(`No VAA ID found for transaction: ${tx}`); + } + } +}; -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees +testFetchVaaId(); + ``` - ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) - ``` + 3. **Run the script** -## Lifecycle of a Message + ```bash + npx tsx test/fetchVaaId.run.ts + ``` -### EVM + If successful, the output will be: -#### Transfer +
+npx tsx test/fetchVaaId.run.ts + +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +VAA ID: 2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/164170 + +
-A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. + If no VAA ID is found, the script will log an error message. -**Events** +### Fetch the Full VAA -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); +Now that you have the VAA ID, we can use it to fetch the full VAA payload from the Wormholescan API. This payload contains the VAA bytes, which will later be used for signature validation. + +Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload. + +```typescript title="src/helpers/vaaHelper.ts" +vaaIds: string[] +): Promise<{ id: string; vaaBytes: string }[]> { + const results: { id: string; vaaBytes: string }[] = []; + + for (const id of vaaIds) { + try { + const response = await axios.get(`${WORMHOLESCAN_API}/signed_vaa/${id}`); + const vaaBytes = response.data.vaaBytes; + results.push({ id, vaaBytes }); + } catch (error) { + console.error(`Error fetching VAA for ${id}:`, error); + } + } + return results; +} ``` -#### Rate Limit +???- code "Try it out: VAA retrieval" + If you want to try the function before moving forward, create a script inside the `test` directory -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. + 1. **Create the script file** -If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. + ```bash + touch test/fetchVaa.run.ts + ``` -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. + 2. **Add the function call** -If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. + ```typescript title="test/fetchVaa.run.ts" + import { fetchVaaId, fetchVaa } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. +const testFetchVaa = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); -**Events** + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } -```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); -``` + for (const vaaId of vaaIds) { + const vaaBytes = await fetchVaa([vaaId]); -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Bytes: ${ + vaaBytes.length > 0 ? vaaBytes[0].vaaBytes : 'Not found' + }` + ); + } + } +}; -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` +testFetchVaa(); + ``` -#### Send + 3. **Run the script** -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). + ```bash + npx tsx test/fetchVaa.run.ts + ``` -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. + If successful, the output will be: -**Events** +
+npx tsx test/fetchVaa.run.ts + +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +VAA Bytes: AQAAAAMNANQSwD/HRPcKp7Yxypl1ON8dZeMBzgYJrd2KYz6l9Tq9K9fj72fYJgkMeMaB9h... + +
-```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); -``` + If no VAA is found, the script will log an error message. -#### Receive +### Validate VAA Signatures -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. +Now, we need to verify its validity. A VAA is only considered valid if it contains signatures from currently active Guardians and is correctly verified by the Wormhole Core contract. -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. +Open `src/helpers/vaaHelper.ts` and add the `checkVaaValidity()` function. This function verifies whether a VAA is valid by submitting it to an Ethereum RPC node and checking for outdated signatures. -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. +Follow these steps to implement the function: -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. +1. **Prepare the VAA for verification** - construct the VAA payload in a format that can be sent to the Wormhole Core contract -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. +2. **Send an `eth_call` request** - submit the VAA to an Ethereum RPC node, calling the `parseAndVerifyVM` function on the Wormhole Core contract -**Events** +3. **Decode the response** - check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); -``` +```typescript title="src/helpers/vaaHelper.ts" +try { + const vaa = Buffer.from(vaaBytes, 'base64'); + vaa[4] = 4; // Set guardian set index to 4 -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` + const result = ( + await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [ + `0x${vaa.toString('hex')}`, + ]), + }, + 'latest', + ], + }) + ).data.result; -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); + const decoded = eth.abi.decodeParameters( + PARSE_AND_VERIFY_VM_ABI.outputs, + result + ); + console.log( + `${decoded.valid ? '✅' : '❌'} VAA Valid: ${decoded.valid}${ + decoded.valid ? '' : `, Reason: ${decoded.reason}` + }` + ); + + return { valid: decoded.valid, reason: decoded.reason }; + } catch (error) { + console.error(`Error checking VAA validity:`, error); + return { valid: false, reason: 'RPC error' }; + } +} ``` -#### Mint or Unlock +???- code "Try it out: VAA Validity" + If you want to try the function before moving forward, create a script inside the `test` directory -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. + 1. **Create the script file** -**Events** + ```bash + touch test/checkVaaValidity.run.ts + ``` -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` + 2. **Add the function call** -### Solana + ```typescript title="test/checkVaaValidity.run.ts" + import { + fetchVaaId, + fetchVaa, + checkVaaValidity, +} from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -#### Transfer +const testCheckVaaValidity = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. + for (const vaaId of vaaIds) { + const vaaData = await fetchVaa([vaaId]); -Depending on the mode and instruction, the following will be produced in the program logs: + if (vaaData.length === 0 || !vaaData[0].vaaBytes) { + console.log(`VAA not found for ID: ${vaaId}`); + continue; + } -```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` + const result = await checkVaaValidity(vaaData[0].vaaBytes); + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Validity:`, + result + ); + } + } +}; -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. +testCheckVaaValidity(); + ``` -#### Rate Limit + 3. **Run the script** -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. + ```bash + npx tsx test/checkVaaValidity.run.ts + ``` -If the transfer amount fits within the current capacity: + If the VAA is valid, the output will be: -- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. +
+npx tsx test/checkVaaValidity.run.ts + +✅ VAA Valid: true + +
-If the transfer amount doesn't fit within the current capacity: + If invalid, the output will include the reason: -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error +
+npx tsx test/checkVaaValidity.run.ts + +❌ VAA Valid: false, Reason: VM signature invalid +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 + +
-#### Send +### Fetch Observations (VAA Signatures) -The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. +Before replacing outdated signatures, we need to fetch the original VAA signatures from Wormholescan. This allows us to compare them with the latest Guardian set and determine which ones need updating. -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. +Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to query the Wormholescan API for observations related to a given VAA. Format the response by converting Guardian addresses to lowercase for consistency, and return an empty array if an error occurs. -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. +```typescript title="src/helpers/vaaHelper.ts" +try { + console.log(`Fetching observations`); -The following will be produced in the program logs: + const response = await axios.get( + `https://api.wormholescan.io/api/v1/observations/${vaaId}` + ); -```ts -Program log: Instruction: ReleaseOutbound + return response.data.map((obs: any) => ({ + guardianAddr: obs.guardianAddr.toLowerCase(), + signature: obs.signature, + })); + } catch (error) { + console.error(`Error fetching observations:`, error); + return []; + } +} ``` -#### Receive +???- code "Try it out: Fetch Observations" + If you want to try the function before moving forward, create a script inside the `test` directory -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. + 1. **Create the script file** -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. + ```bash + touch test/fetchObservations.run.ts + ``` -The following will be produced in the program logs: + 2. **Add the function call** -```ts -Program log: Instruction: ReceiveMessage -``` + ```typescript title="test/fetchObservations.run.ts" + import { fetchVaaId, fetchObservations } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. +const testFetchObservations = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); -The following will be produced in the program logs: + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } -```ts -Program log: Instruction: Redeem -``` + for (const vaaId of vaaIds) { + const observations = await fetchObservations(vaaId); -#### Mint or Unlock + if (observations.length === 0) { + console.log(`No observations found for VAA ID: ${vaaId}`); + continue; + } -The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nObservations:`, + observations + ); + } + } +}; -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. +testFetchObservations(); + ``` -Depending on the mode and instruction, the following will be produced in the program logs: + 3. **Run the script** -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock -``` ---- END CONTENT --- + ```bash + npx tsx test/fetchObservations.run.ts + ``` -Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement FAQs -description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. -categories: Settlement, Transfer ---- + If successful, the output will be: -# Wormhole Settlement FAQs +
+npx tsx test/fetchObservations.run.ts + +Fetching observations +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +Observations: [ { guardianAddr: '0xda798f6896a3331f64b48c12d1d57fd9cbe70811', signature: + 'ZGFlMDYyOGNjZjFjMmE0ZTk5YzE2OThhZjAzMDM4NzZlYTM1OWMxMzczNDA3YzdlMDMxZTkyNzk0ODkwYjRiYjRiOWFmNzM3NjRiMzIyOTE0ZTQwYzNlMjllMWEzNmM2NTc3ZDc5ZTdhNTM2MzA5YjA4YjExZjE3YzE3MDViNWIwMQ==' + }, { guardianAddr: '0x74a3bf913953d695260d88bc1aa25a4eee363ef0', signature: + 'MzAyOTU4OGU4MWU0ODc0OTAwNDU3N2EzMGZlM2UxMDJjOWYwMjM0NWVhY2VmZWQ0ZGJlNTFkNmI3YzRhZmQ5ZTNiODFjNTg3MDNmYzUzNmJiYWFiZjNlODc1YTY3OTQwMGE4MmE3ZjZhNGYzOGY3YmRmNDNhM2VhNGQyNWNlNGMwMA==' + }, +...] + +
-## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? + If no observations are found, the script will log an error message. -Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. +### Fetch the Latest Guardian Set -## What happens if no solver participates in the auction? +Now that we have the original VAA signatures, we must fetch the latest Guardian set from Wormholescan. This will allow us to compare the stored signatures with the current Guardians and determine which signatures need replacing. -If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. +Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set. -## What guarantees does Wormhole Settlement provide for message execution? +```typescript title="src/helpers/vaaHelper.ts" +export async function fetchGuardianSet() { + try { + console.log('Fetching current guardian set'); -After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). + const response = await axios.get(`${WORMHOLESCAN_API}/guardianset/current`); + const guardians = response.data.guardianSet.addresses.map((addr: string) => + addr.toLowerCase() + ); + const guardianSet = response.data.guardianSet.index; -If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. ---- END CONTENT --- + return [guardians, guardianSet]; + } catch (error) { + console.error('Error fetching guardian set:', error); + return []; + } +} +``` -Doc-Content: https://wormhole.com/docs/build/transfers/settlement/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement -description: Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. -categories: Settlement, Transfer ---- +???- code "Try it out: Fetch Guardian Set" + If you want to try the function before moving forward, create a script inside the `test` directory -# Wormhole Settlement + 1. **Create the script file** -## Get Started + ```bash + touch test/fetchGuardianSet.run.ts + ``` -This section provides resources to build with Wormhole Settlement, including integrating the Liquidity Layer into your application and running a Solver for efficient cross-chain asset transfers. + 2. **Add the function call** -
+ ```typescript title="test/fetchGuardianSet.run.ts" + import { fetchGuardianSet } from '../src/helpers/vaaHelper'; -- :octicons-code-16:{ .lg .middle } **Build on the Liquidity Layer** +const testFetchGuardianSet = async () => { + const [guardians, guardianSetIndex] = await fetchGuardianSet(); - --- + console.log('Current Guardian Set Index:', guardianSetIndex); + console.log('Guardian Addresses:', guardians); +}; - Integrate seamlessly with Wormhole's Liquidity Layer, learn key EVM contract functions for fast and secure cross-chain transfers. +testFetchGuardianSet(); + ``` - [:custom-arrow: Build on the Liquidity layer](/docs/products/settlement/guides/liquidity-layer/) + 3. **Run the script** -- :octicons-code-16:{ .lg .middle } **Run a Settlement Solver** + ```bash + npx tsx test/fetchGuardianSet.run.ts + ``` - --- + If successful, the output will be: - Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +
+npx tsx test/fetchGuardianSet.run.ts + +Fetching current guardian set +Current Guardian Set Index: 4 +Guardian Addresses: [ + '0x5893b5a76c3f739645648885bdccc06cd70a3cd3', + '0xff6cb952589bde862c25ef4392132fb9d4a42157', + '0x114de8460193bdf3a2fcf81f86a09765f4762fd1', + '0x107a0086b32d7a0977926a205131d8731d39cbeb', + +...] + +
- [:custom-arrow: Run a Solver](/docs/products/settlement/guides/solver/) + If an error occurs while fetching the Guardian set, a `500` status error will be logged. -
---- END CONTENT --- +### Replace Outdated Signatures -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- +With the full VAA, Guardian signatures, and the latest Guardian set, we can now update outdated signatures while maintaining the required signature count. -# Build on the Wormhole Liquidity Layer +1. **Create the `replaceSignatures()` function** - open `src/helpers/vaaHelper.ts` and add the function header. To catch and handle errors properly, all logic will be wrapped inside a `try` block -## Introduction + ```typescript title="src/helpers/vaaHelper.ts" + vaa: string | Uint8Array, + observations: { guardianAddr: string; signature: string }[], + currentGuardians: string[], + guardianSetIndex: number +) { + console.log('Replacing Signatures...'); -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. + try { + // Add logic in the following steps here + console.error('Unexpected error in replaceSignatures:', error); + } +} + ``` -## EVM Functions + - **`vaa`** - original VAA bytes + - **`observations`** - observed signatures from the network + - **`currentGuardians`** - latest Guardian set + - **`guardianSetIndex`** - current Guardian set index -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. +2. **Validate input data** - ensure all required parameters are present before proceeding. If any required input is missing, the function throws an error to prevent execution with incomplete data. The Guardian set should never be empty; if it is, this likely indicates an error in fetching the Guardian set in a previous step -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. + ```typescript + if (currentGuardians.length === 0) + throw new Error('Guardian set is empty.'); + if (observations.length === 0) throw new Error('No observations provided.'); + ``` -### Fast Market Order +3. **Filter valid signatures** - remove signatures from inactive Guardians, keeping only valid ones. If there aren't enough valid signatures to replace the outdated ones, execution is halted to prevent an incomplete or invalid VAA -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` + ```typescript + currentGuardians.includes(sig.guardianAddr) + ); -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` + if (validSigs.length === 0) + throw new Error('No valid signatures found. Cannot proceed.'); + ``` -??? interface "Parameters `placeFastMarketOrder()`" +4. **Convert valid signatures** - ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components - `amountIn` ++"uint128"++ + ```typescript + .map((sig) => { + try { + const sigBuffer = Buffer.from(sig.signature, 'base64'); + // If it's 130 bytes, it's hex-encoded and needs conversion + const sigBuffer1 = + sigBuffer.length === 130 + ? Buffer.from(sigBuffer.toString(), 'hex') + : sigBuffer; - The amount to transfer. + const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); + const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); + const vRaw = sigBuffer1[64]; + const v = vRaw < 27 ? vRaw : vRaw - 27; - --- + return { + guardianIndex: currentGuardians.indexOf(sig.guardianAddr), + signature: new Signature(r, s, v), + }; + } catch (error) { + console.error( + `Failed to process signature for guardian: ${sig.guardianAddr}`, + error + ); + return null; + } + }) + .filter( + (sig): sig is { guardianIndex: number; signature: Signature } => + sig !== null + ); // Remove null values + ``` - `targetChain` ++"uint16"++ +5. **Deserialize the VAA** - convert the raw VAA data into a structured format for further processing - Target chain ID. + ```typescript + try { + parsedVaa = deserialize('Uint8Array', vaa); + } catch (error) { + throw new Error(`Error deserializing VAA: ${error}`); + } + ``` - --- +6. **Identify outdated signatures** - compare the current VAA signatures with the newly formatted ones to detect which signatures belong to outdated Guardians. Remove these outdated signatures to ensure only valid ones remain - `redeemer` ++"bytes32"++ + ```typescript + .filter( + (vaaSig) => + !formattedSigs.some( + (sig) => sig.guardianIndex === vaaSig.guardianIndex + ) + ) + .map((sig) => sig.guardianIndex); - Redeemer contract address. + console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); - --- + let updatedSignatures = parsedVaa.signatures.filter( + (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) + ); + ``` - `redeemerMessage` ++"bytes"++ +7. **Replace outdated signatures** - substitute outdated signatures with valid ones while maintaining the correct number of signatures. If there aren’t enough valid replacements, execution stops - An arbitrary payload for the redeemer. + ```typescript + (sig) => + !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) + ); - --- + // Check if we have enough valid signatures to replace outdated ones** + if (outdatedGuardianIndexes.length > validReplacements.length) { + console.warn( + `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` + ); + return; + } - `maxFee` ++"uint128"++ + updatedSignatures = [ + ...updatedSignatures, + ...validReplacements.slice(0, outdatedGuardianIndexes.length), + ]; - The maximum fee the user wants to pay to execute a fast transfer. + updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); + ``` - --- +8. **Serialize the updated VAA** - reconstruct the VAA with the updated signatures and convert it into a format suitable for submission - `deadline` ++"uint32"++ + ```typescript + ...parsedVaa, + guardianSet: guardianSetIndex, + signatures: updatedSignatures, + }; - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. + let patchedVaa: Uint8Array; + try { + patchedVaa = serialize(updatedVaa); + } catch (error) { + throw new Error(`Error serializing updated VAA: ${error}`); + } + ``` -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. +9. **Send the updated VAA for verification and handle errors** - submit the updated VAA to an Ethereum RPC node for validation, ensuring it can be proposed for Guardian approval. If an error occurs during submission or signature replacement, log the issue and prevent further execution -### Market Order + ```typescript + if (!(patchedVaa instanceof Uint8Array)) + throw new Error('Patched VAA is not a Uint8Array!'); -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. + const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` + console.log('Sending updated VAA to RPC...'); -??? interface "Parameters `placeMarketOrder()`" + const result = await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), + }, + 'latest', + ], + }); - `amountIn` ++"uint128"++ + const verificationResult = result.data.result; + console.log('Updated VAA (hex):', vaaHex); + return verificationResult; + } catch (error) { + throw new Error(`Error sending updated VAA to RPC: ${error}`); + } + ``` - The amount to transfer. +???- code "Complete Function" + ```typescript + vaa: string | Uint8Array, + observations: { guardianAddr: string; signature: string }[], + currentGuardians: string[], + guardianSetIndex: number +) { + console.log('Replacing Signatures...'); - --- + try { + if (!vaa) throw new Error('VAA is undefined or empty.'); + if (currentGuardians.length === 0) + throw new Error('Guardian set is empty.'); + if (observations.length === 0) throw new Error('No observations provided.'); - `targetChain` ++"uint16"++ + const validSigs = observations.filter((sig) => + currentGuardians.includes(sig.guardianAddr) + ); - Target chain ID. + if (validSigs.length === 0) + throw new Error('No valid signatures found. Cannot proceed.'); - --- + const formattedSigs = validSigs + .map((sig) => { + try { + const sigBuffer = Buffer.from(sig.signature, 'base64'); + // If it's 130 bytes, it's hex-encoded and needs conversion + const sigBuffer1 = + sigBuffer.length === 130 + ? Buffer.from(sigBuffer.toString(), 'hex') + : sigBuffer; - `redeemer` ++"bytes32"++ + const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); + const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); + const vRaw = sigBuffer1[64]; + const v = vRaw < 27 ? vRaw : vRaw - 27; - Redeemer contract address. + return { + guardianIndex: currentGuardians.indexOf(sig.guardianAddr), + signature: new Signature(r, s, v), + }; + } catch (error) { + console.error( + `Failed to process signature for guardian: ${sig.guardianAddr}`, + error + ); + return null; + } + }) + .filter( + (sig): sig is { guardianIndex: number; signature: Signature } => + sig !== null + ); // Remove null values - --- + let parsedVaa: VAA<'Uint8Array'>; + try { + parsedVaa = deserialize('Uint8Array', vaa); + } catch (error) { + throw new Error(`Error deserializing VAA: ${error}`); + } - `redeemerMessage` ++"bytes"++ + const outdatedGuardianIndexes = parsedVaa.signatures + .filter( + (vaaSig) => + !formattedSigs.some( + (sig) => sig.guardianIndex === vaaSig.guardianIndex + ) + ) + .map((sig) => sig.guardianIndex); - An arbitrary payload for the redeemer. + console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- + let updatedSignatures = parsedVaa.signatures.filter( + (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) + ); -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- + const validReplacements = formattedSigs.filter( + (sig) => + !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) + ); -# Run a Wormhole Settlement Solver + // Check if we have enough valid signatures to replace outdated ones** + if (outdatedGuardianIndexes.length > validReplacements.length) { + console.warn( + `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` + ); + return; + } -## Introduction + updatedSignatures = [ + ...updatedSignatures, + ...validReplacements.slice(0, outdatedGuardianIndexes.length), + ]; -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. + updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); -A Solver is an off-chain agent responsible for: + const updatedVaa: VAA<'Uint8Array'> = { + ...parsedVaa, + guardianSet: guardianSetIndex, + signatures: updatedSignatures, + }; -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana + let patchedVaa: Uint8Array; + try { + patchedVaa = serialize(updatedVaa); + } catch (error) { + throw new Error(`Error serializing updated VAA: ${error}`); + } -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. + try { + if (!(patchedVaa instanceof Uint8Array)) + throw new Error('Patched VAA is not a Uint8Array!'); -## Background + const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: + console.log('Sending updated VAA to RPC...'); -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners + const result = await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), + }, + 'latest', + ], + }); -These instructions work together to carry out the auction as follows: + const verificationResult = result.data.result; + console.log('Updated VAA (hex):', vaaHex); + return verificationResult; + } catch (error) { + throw new Error(`Error sending updated VAA to RPC: ${error}`); + } + } catch (error) { + console.error('Unexpected error in replaceSignatures:', error); + } +} + ``` -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent +## Create Script to Replace Outdated VAA Signatures -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. +Now that we have all the necessary helper functions, we will create a script to automate replacing outdated VAA signatures. This script will retrieve a transaction’s VAA sequentially, check its validity, fetch the latest Guardian set, and update its signatures. By the end, it will output a correctly signed VAA that can be proposed for Guardian approval. -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. +1. **Open the file** - inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs -## Testnet Example Solver + ```typescript title="src/scripts/replaceSignatures.ts" + fetchVaaId, + fetchVaa, + checkVaaValidity, + fetchObservations, + fetchGuardianSet, + replaceSignatures, +} from '../helpers/vaaHelper'; +import { TXS } from '../config/constants'; + ``` -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. +2. **Define the main execution function** - add the following function inside `src/scripts/replaceSignatures.ts` to process each transaction in `TXS`, going step by step through the signature replacement process -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. + ```typescript + try { + for (const tx of TXS) { + console.log(`\nProcessing TX: ${tx}\n`); -### Prerequisites + // 1. Fetch Transaction VAA IDs: + const vaaIds = await fetchVaaId([tx]); + if (!vaaIds.length) continue; -In order to build and install dependencies locally in this repo, you will need: + // 2. Fetch VAA Data: + const vaaData = await fetchVaa(vaaIds); + if (!vaaData.length) continue; -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} + const vaaBytes = vaaData[0].vaaBytes; + if (!vaaBytes) continue; -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: + // 3. Check VAA Validity: + const { valid } = await checkVaaValidity(vaaBytes); + if (valid) continue; -```sh -make dependencies -``` + // 4. Fetch Observations (VAA signatures): + const observations = await fetchObservations(vaaIds[0]); -### Set up Config + // 5. Fetch Current Guardian Set: + const [currentGuardians, guardianSetIndex] = await fetchGuardianSet(); -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. + // 6. Replace Signatures: + const response = await replaceSignatures( + Buffer.from(vaaBytes, 'base64'), + observations, + currentGuardians, + guardianSetIndex + ); -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 + if (!response) continue; } - ] + } catch (error) { + console.error('❌ Error in execution:', error); + process.exit(1); + } } -``` - -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. + ``` -### Listen to Activity +3. **Make the script executable** - ensure it runs when executed -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. + ```typescript + + ``` -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` + To run the script, use the following command: -You should see output resembling: + ```bash + npx tsx src/scripts/replaceSignatures.ts + ``` -
- Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 +
+npx tsx src/scripts/replaceSignatures.ts + +Processing TX: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +❌ VAA Valid: false, Reason: VM signature invalid +Fetching observations +Fetching current guardian set +Replacing Signatures... +Outdated Guardian Indexes: [ 0 ] +Sending updated VAA to RPC... +Updated VAA (hex): 0x01000000040d010019447b72d51e33923a3d6b28496ccd3722d5f1e33e2... +
-To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: +The script logs each step, skipping valid VAAs, replacing outdated signatures for invalid VAAs, and logging any errors. It then completes with a valid VAA ready for submission. -=== "Linux" +## Resources - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` +You can explore the complete project and find all necessary scripts and configurations in Wormhole's [demo GitHub repository](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank}. -=== "MacOS" +The demo repository includes a bonus script to check the VAA redemption status on Ethereum and Solana, allowing you to verify whether a transaction has already been redeemed on the destination chain. - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` +## Conclusion -### Running the Example Solver +You've successfully built a script to fetch, validate, and replace outdated signatures in VAAs using Wormholescan and the Wormhole SDK. -Using the same config for your publisher, run the example solver with the command below. +It's important to note that this tutorial does not update VAAs in the Wormhole network. Before redeeming the VAA, you must propose it for Guardian approval to finalize the process. +--- END CONTENT --- -```sh -CONFIG=path/to/config.json make run-solver -``` +Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: MultiGov Architecture +description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. +categories: MultiGov +--- -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. +# MultiGov Architecture -This process reads the following environment variables: +MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` +## Key Components -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. +### Hub Chain Contracts -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. +The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. + - **`HubGovernor`** - central governance contract managing proposals and vote tallying + - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` + - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains + - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed + - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals + - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible -An address lookup table is required to execute some transactions. Use the command below to create one. +### Spoke Chains Contracts -```sh -CONFIG=path/to/config.json make create-lut -``` +Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. + - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub + - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub + - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters + - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury -The example solver has the following toggles depending on which orders you want to fulfill: +### Spoke Solana Staking Program -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` +The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. +The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: -This example solver does NOT do the following: + - **`GlobalConfig`** - global program configuration + - **`StakeAccountMetadata`** - stores user's staking information + - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts + - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens + - **`CheckpointData`** - tracks delegation history + - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain + - **`GuardianSignatures`** - stores guardian signatures for message verification + - **`ProposalData`** - stores data about a specific proposal, including votes and start time + - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal + - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol + - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution + - **`VestingBalance`** - stores total vesting balance and related staking information of a vester + - **`VestingConfig`** - defines vesting configuration, including mint and admin details + - **`Vesting`** - represents individual vesting allocations with maturation data + - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- +Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. -Doc-Content: https://wormhole.com/docs/build/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Get Started with Token Bridge -description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -categories: Token-Bridge, Transfer ---- +## System Workflow -# Token Bridge +The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. -## Introduction +### EVM Governance Workflow -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +The EVM-based MultiGov workflow follows these steps: -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +1. **Proposal creation**: + 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method + 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold +2. **Proposal metadata distribution**: + 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` + 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details +3. **Voting process**: + 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` + 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole + 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution + 3. After the timelock delay, the proposal can be executed on the hub chain + 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains + 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` -## Prerequisites +### Solana Governance Workflow -To interact with the Wormhole Token Bridge, you'll need the following: +The Solana-based MultiGov workflow follows these steps: -- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +1. **Proposal creation**: + 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold + 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function + 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution -## How to Interact with Token Bridge Contracts +2. **Proposal metadata distribution**: + 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** + 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program + 3. The proposal data is verified to ensure it matches the expected format + 4. Guardian signatures are posted using the `PostSignatures` instruction + 5. Once validated, the proposal is stored on-chain -The primary functions of the Token Bridge contracts revolve around: +3. **Voting process**: + 1. Users vote on proposals stored in the `ProposalData` account on Solana + 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) + 3. Eligibility and vote weight are verified using historical voter checkpoint data + 4. A **Query Wormhole** request retrieves vote data from a Solana PDA + 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification + 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision -- **Attesting a token** - registering a new token for cross-chain transfers -- **Transferring tokens** - locking and minting tokens across chains -- **Transferring tokens with a payload** - including additional data with transfers +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution + 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain + 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana + 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions -### Attest a token +## Cross-Chain Communication -Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. +MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. -The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. +## Security Measures -```solidity -function attestToken( - address tokenAddress, - uint32 nonce -) external payable returns (uint64 sequence); -``` +- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting + - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions +- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review +- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol -??? interface "Parameters" +## Detailed Architecture Diagram - `tokenAddress` ++"address"++ - - The contract address of the token to be attested. +This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. - --- + +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) +--- END CONTENT --- - `nonce` ++"uint32"++ +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ +--- BEGIN CONTENT --- +--- +title: MultiGov FAQs +description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +categories: MultiGov +--- - An arbitrary value provided by the caller to ensure uniqueness. +# FAQs -??? interface "Returns" +## What is MultiGov? - `sequence` ++"uint64"++ - - A unique identifier for the attestation transaction. +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. -When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. +## How does MultiGov ensure security in cross-chain communication? -You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. +MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: -### Transfer Tokens +- Message origin verification to prevent unauthorized governance actions +- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states +- Authorized participant validation to maintain the integrity of the governance process +- Replay attack prevention by tracking executed messages -Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. +## Can MultiGov integrate with any blockchain? -Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. -```solidity -function transferTokens( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint256 arbiterFee, - uint32 nonce -) external payable returns (uint64 sequence); -``` +## How are votes aggregated across different chains? -??? interface "Parameters" +Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. - `token` ++"address"++ - - The address of the token being transferred. +## Can governance upgrade from a single chain to MultiGov? - --- +Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. - `amount` ++"uint256"++ - The amount of tokens to be transferred. +## How can I create a proposal in MultiGov? - --- +Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. +## How do I vote on a proposal if I hold tokens on a spoke chain? - --- +You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. +## How are approved proposals executed across multiple chains? - --- +When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. - `arbiterFee` ++"uint256"++ - Optional fee to be paid to an arbiter for relaying the transfer. +## What are the requirements for using MultiGov? - --- +To use MultiGov, your DAO must meet the following requirements: - `nonce` ++"uint32"++ - A unique identifier for the transaction. +- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance +- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature -??? interface "Returns" +## What do I need to set up MultiGov for my project? - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. +Get started by filling out the form below: + +https://www.tally.xyz/get-started + +Tally will reach out to help get your DAO set up with MultiGov. -Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. +To set up testing MultiGov for your DAO, you'll need: -```solidity -function completeTransfer(bytes memory encodedVm) external; -``` +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed +- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) +- Modify and deploy the hub and spoke contracts using the provided scripts +- Set up the necessary environment variables and configurations -??? interface "Parameters" +## Can MultiGov be used with non-EVM chains? - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. +The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. -!!!note - - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain +## How can I customize voting parameters in MultiGov? -### Transfer tokens with payload +Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. -While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. +Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. -Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. +## How does MultiGov handle potential network issues or temporary chain unavailability? -```solidity -function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload -) external payable returns (uint64 sequence); -``` +MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: -??? interface "Parameters" +1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable +2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems +3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through +4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline - `token` ++"address"++ - - The address of the token being transferred. +However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. - --- +## How does MultiGov differ from traditional DAO governance? - `amount` ++"uint256"++ - The amount of tokens to be transferred. +Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. - --- +## What are the main components of MultiGov? - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. +The main components of MultiGov include: - --- +- **Hub chain** - central coordination point for governance activities +- **Spoke chains** - additional chains where token holders can participate in governance +- **Wormhole integration** - enables secure cross-chain message passing +- **Governance token** - allows holders to participate in governance across all integrated chains +--- END CONTENT --- - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. +Doc-Content: https://wormhole.com/docs/products/multigov/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ +--- BEGIN CONTENT --- +--- +title: Deploy MultiGov on EVM Chains +description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +categories: MultiGov +--- - `nonce` ++"uint32"++ - A unique identifier for the transaction. +# Deploy MultiGov on EVM Chains - --- +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. - `payload` ++"bytes memory"++ - Arbitrary data payload attached to the transaction. +Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. +## Prerequisites -After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. +To interact with MultiGov, you'll need the following: -Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. +- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} +- Install [Git](https://git-scm.com/downloads){target=\_blank} +- Clone the repository: + ```bash + git clone https://github.com/wormhole-foundation/multigov + cd evm # for evm testing/deploying + ``` -```solidity -function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); -``` +## Development Setup -??? interface "Parameters" +For developers looking to set up a local MultiGov environment: - `encodedVm` ++"bytes memory"++ +1. Install dependencies: + ```bash + forge install + ``` - The signed VAA containing the transfer details. +2. Set up environment variables: + ```bash + cp .env.example .env + ``` -??? interface "Returns" + Edit `.env` with your specific [configuration](#configuration){target=\_blank} - `bytes memory` +3. Compile contracts: + ```bash + forge build + ``` - The extracted payload data. +4. Deploy contracts (example for Sepolia testnet): -## Source Code References + For hub chains: + ```bash + forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast + ``` -For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: + For spoke chains (e.g., Optimism Sepolia): + ```bash + forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast + ``` -- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} -- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} +## Configuration -## Portal Bridge +When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: -A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +### Hub Governor Key Parameters -## FAQs +- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day +- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal +- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful +- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day -### Can ownership of wrapped tokens be transferred from the Token Bridge? + !!! note + This helps mitigate cross-chain double voting. -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +### Hub Proposal Extender Key Parameters - - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge +- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours +- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour -The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. +### Spoke Vote Aggregator Key Parameters -Relevant contracts: +- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day - - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} - - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} + !!! note + This is crucial for mitigating cross-chain double voting -### How do I update the metadata of a wrapped token? +### Hub Evm Spoke Vote Aggregator Key Parameters -Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. +- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +### Updateable Governance Parameters -You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. +The following key parameters can be updated through governance proposals: -### How can I update my wrapped token image on Solscan? +- `votingDelay` - delay before voting starts (in seconds) +- `votingPeriod` - duration of the voting period (in seconds) +- `proposalThreshold` - threshold for creating proposals (in tokens) +- `quorum` - number of votes required for quorum +- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) +- `voteWeightWindow` - window for vote weight checkpoints (in seconds) +- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time -Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. +These parameters can be queried using their respective getter functions on the applicable contract. -To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. +To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/glossary/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics +title: MultiGov Deployment to Solana +description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. +categories: MultiGov --- -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID +# Deploy MultiGov on Solana -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. -## Consistency Level +## Prerequisites -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +To deploy MultiGov on Solana, ensure you have the following installed: -## Delivery Provider + - Install [Git](https://git-scm.com/downloads){target=\_blank} + - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** + - Install [Solana CLI](https://docs.anza.xyz/cli/install/){target=\_blank} **`v1.18.20`** + - Install [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`v0.30.1`** + - Install [Rust](https://www.rust-lang.org/tools/install){target=\_blank} **`v1.80.1`** + - Install [Docker](https://www.docker.com/get-started/){target=\_blank} + - Clone the repository: + ```bash + git clone https://github.com/wormhole-foundation/multigov.git + cd multigov/solana/ + ``` -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +## Build the Project -## Emitter +To create a verifiable build of the MultiGov Staking Program, run the following command: -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +```bash +./scripts/build_verifiable_staking_program.sh +``` -## Finality +Once the build is complete, the compiled artifacts will be available in the `target` folder. -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +## Set Up the Deployer Account -## Guardian +For a successful deployment, you need a funded deployer account on Solana. This account will store the program and execute deployment transactions. -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +In this section, you will create a new keypair, check the account balance, and ensure it has enough SOL tokens to cover deployment costs. If needed, you can fund the account using different methods before deploying. -## Guardian Network +### Generate a New Keypair -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +To create a new keypair and save it to a file, run the following command: -## Guardian Set +```bash +solana-keygen new --outfile ./app/keypairs/deployer.json +``` -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +### Check the Deployer Account Address -## Heartbeat +To retrieve the public address of the newly created keypair, run the following command: -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +```bash +solana address -k ./app/keypairs/deployer.json +``` -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +### Check the Deployer Account Balance -## Observation +To verify the current balance of the deployer account, run the following command: -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +```bash +solana balance -k ./app/keypairs/deployer.json +``` -## Relayer +!!! warning + When deploying the MultiGov Staking Program, the deployer account must have enough SOL to cover deployment costs and transaction fees. -A relayer is any process that delivers VAAs to a destination. + - 7.60219224 SOL for deployment costs + - 0.00542 SOL for transaction fees -## Sequence +### Fund the Deployer Account -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +If the account does not have enough SOL, use one of the following methods to add funds. -## Spy + - **Transfer SOL from another account** - if you already have SOL in another account, transfer it using a wallet (Phantom, Solflare, etc.) or in the terminal -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + ```bash + solana transfer --from /path/to/funder.json + ``` -## VAA + - **Request an airdrop (devnet only)** - if deploying to devnet, you can request free SOL -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + ```bash + solana airdrop 2 -k ./app/keypairs/deployer.json + ``` -## Validator + - **Use a Solana faucet (devnet only)** - you can use online faucets to receive 10 free SOL -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- + - [Solana Faucet](https://faucet.solana.com/){target=\_blank} -Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: MultiGov Architecture -description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. -categories: MultiGov ---- +## Deploy the MultiGov Staking Program -# MultiGov Architecture +With the deployer account set up and funded, you can deploy the MultiGov Staking Program to the Solana blockchain. This step involves deploying the program, verifying the deployment, and ensuring the necessary storage and metadata are correctly configured. Once the IDL is initialized, the program will be ready for further setup and interaction. -MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. +### Deploy the Program -## Key Components +Deploy the MultiGov Staking Program using Anchor: -### Hub Chain Contracts +```bash +anchor deploy --provider.cluster https://api.devnet.solana.com --provider.wallet ./app/keypairs/deployer.json +``` -The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. +### Verify the Deployment - - **`HubGovernor`** - central governance contract managing proposals and vote tallying - - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` - - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains - - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed - - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals - - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible +After deployment, check if the program is successfully deployed by running the following command: -### Spoke Chains Contracts +```bash +solana program show INSERT_PROGRAM_ID +``` -Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. +### Extend Program Storage - - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub - - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub - - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters - - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury +If the deployed program requires additional storage space for updates or functionality, extend the program storage using the following command: -### Spoke Solana Staking Program +```bash +solana program extend INSERT_PROGRAM_ID 800000 +``` -The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. +### Initialize the IDL -The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: +To associate an IDL file with the deployed program, run the following command: - - **`GlobalConfig`** - global program configuration - - **`StakeAccountMetadata`** - stores user's staking information - - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts - - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens - - **`CheckpointData`** - tracks delegation history - - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain - - **`GuardianSignatures`** - stores guardian signatures for message verification - - **`ProposalData`** - stores data about a specific proposal, including votes and start time - - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal - - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol - - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution - - **`VestingBalance`** - stores total vesting balance and related staking information of a vester - - **`VestingConfig`** - defines vesting configuration, including mint and admin details - - **`Vesting`** - represents individual vesting allocations with maturation data - - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows +```bash +anchor idl init --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json INSERT_PROGRAM_ID +``` -Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. +## Configure the Staking Program -## System Workflow +The final step after deploying the MultiGov Staking Program is configuring it for proper operation. This includes running a series of deployment scripts to initialize key components and set important governance parameters. These steps ensure that staking, governance, and cross-chain communication function as expected. -The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. +### Run Deployment Scripts -### EVM Governance Workflow +After deploying the program and initializing the IDL, execute the following scripts **in order** to set up the staking environment and necessary accounts. -The EVM-based MultiGov workflow follows these steps: +1. Initialize the MultiGov Staking Program with default settings: -1. **Proposal creation**: - 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method - 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold -2. **Proposal metadata distribution**: - 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` - 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details -3. **Voting process**: - 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` - 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole - 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution - 3. After the timelock delay, the proposal can be executed on the hub chain - 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains - 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` + ```bash + npx ts-node app/deploy/01_init_staking.ts + ``` -### Solana Governance Workflow +2. Create an Account Lookup Table (ALT) to optimize transaction processing: -The Solana-based MultiGov workflow follows these steps: + ```bash + npx ts-node app/deploy/02_create_account_lookup_table.ts + ``` -1. **Proposal creation**: - 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold - 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function - 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution +3. Set up airlock accounts: -2. **Proposal metadata distribution**: - 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** - 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program - 3. The proposal data is verified to ensure it matches the expected format - 4. Guardian signatures are posted using the `PostSignatures` instruction - 5. Once validated, the proposal is stored on-chain + ```bash + npx ts-node app/deploy/03_create_airlock.ts + ``` -3. **Voting process**: - 1. Users vote on proposals stored in the `ProposalData` account on Solana - 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) - 3. Eligibility and vote weight are verified using historical voter checkpoint data - 4. A **Query Wormhole** request retrieves vote data from a Solana PDA - 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification - 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision +4. Deploy a metadata collector: -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution - 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain - 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana - 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions + ```bash + npx ts-node app/deploy/04_create_spoke_metadata_collector.ts + ``` -## Cross-Chain Communication +5. Configure vote weight window lengths: -MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. + ```bash + npx ts-node app/deploy/05_initializeVoteWeightWindowLengths.ts + ``` -## Security Measures +6. Deploy the message executor for handling governance messages: -- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting - - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions -- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review -- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol + ```bash + npx ts-node app/deploy/06_create_message_executor.ts + ``` -## Detailed Architecture Diagram +### Set MultiGov Staking Program Key Parameters -This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. +When deploying MultiGov on Solana, several key parameters need to be set. Here are the most important configuration points: - -![detailed multigov architecture diagram](/docs/images/learn/governance/multigov-detailed.webp) + - `maxCheckpointsAccountLimit` ++"u64"++ - the maximum number of checkpoints an account can have. For example, `654998` is used in production, while `15` might be used for testing + - `hubChainId` `u16` - the chain ID of the hub network where proposals are primarily managed. For example, `10002` for Sepolia testnet + - `hubProposalMetadata` ++"[u8; 20]"++ - an array of bytes representing the address of the Hub Proposal Metadata contract on Ethereum. This is used to identify proposals from the hub + - `voteWeightWindowLength` ++"u64"++ - specifies the length of the checkpoint window in seconds in which the minimum voting weight is taken. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The vote weight window helps solve problems such as manipulating votes in a chain + - `votingTokenMint` ++"Pubkey"++ - the mint address of the token used for voting + - `governanceAuthority` ++"Pubkey"++ - the account's public key with the authority to govern the staking system. The `governanceAuthority` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup + - `vestingAdmin` ++"Pubkey"++ - the account's public key for managing vesting operations. The `vestingAdmin` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup + - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ --- BEGIN CONTENT --- --- -title: MultiGov Theoretical FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +title: Upgrading MultiGov on EVM +description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. categories: MultiGov --- -# FAQs +# Upgrade MultiGov Contracts on EVM Chains + +MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. -## General Questions +## Key Considerations for Upgrades -### What is MultiGov? +- **`HubGovernor`**: + - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. +- **`HubVotePool`**: + - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` + - Requires re-registering all spokes on the new `HubVotePool` + - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` + - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` -### How does MultiGov differ from traditional DAO governance? +- **`SpokeMessageExecutor`**: + - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern + - Stores critical parameters in `SpokeMessageExecutorStorage` -Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. +- **`HubEvmSpokeAggregateProposer`**: + - Needs redeployment if `HubGovernor` changes + - Requires re-registering all spokes after redeployment -### What are the main components of MultiGov? +- **`HubProposalMetadata`**: + - Needs redeployment if `HubGovernor` changes, as it references `HubGovernor` as a parameter -The main components of MultiGov include: +- **`SpokeMetadataCollector`**: + - Requires redeployment if the hub chain ID changes or if `HubProposalMetadata` changes -- **Hub chain** - central coordination point for governance activities -- **Spoke chains** - additional chains where token holders can participate in governance -- **Wormhole integration** - enables secure cross-chain message passing -- **Governance token** - allows holders to participate in governance across all integrated chains +## Process for Major System Upgrade + +1. **New `HubGovernor` deployment**: + - Deploy the new `HubGovernor` contract +1. **Component redeployment**: + - Redeploy `HubEvmSpokeAggregateProposer` with the new `HubGovernor` address + - Redeploy `HubProposalMetadata` referencing the new `HubGovernor` + - If hub chain ID changes, redeploy `SpokeMetadataCollector` on all spoke chains +1. **`HubVotePool` update**: + - Set the new `HubVotePool` on the new `HubGovernor` + - Register all spokes on the new `HubVotePool` + - Register the query type and implementation for vote decoding (`HubEvmSpokeVoteDecoder`) +1. **Spoke re-registration**: + - Re-register all spokes on the new `HubEvmSpokeAggregateProposer` +1. **Verification and testing**: + - Conduct thorough testing of the new system setup + - Verify all cross-chain interactions are functioning correctly +1. **System transition and deprecation**: + - Create a proposal to switch the timelock to the new governor + - Communicate clearly to the community what changes were made +1. **Monitoring**: + - Implement a transition period where the new system is closely monitored + - Address any issues that arise promptly + +## Important Considerations + +- Always prioritize system stability, upgrades should only be performed when absolutely necessary +- Thoroughly audit all new contract implementations before proposing an upgrade +- Account for all affected components across all chains in the upgrade plan +- Provide comprehensive documentation for the community about the upgrade process and any changes in functionality +- Always test upgrades extensively on testnets before implementing in production --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/governance/ +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ --- BEGIN CONTENT --- --- -title: Learn about MultiGov -description: Explore the MultiGov documentation for a comprehensive guide covering architecture, deployment, upgrading, integration, and FAQs. +title: Upgrading MultiGov on Solana +description: Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. categories: MultiGov --- -# MultiGov +# Upgrade MultiGov Contracts on Solana -Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. Get an introduction to the core concepts, explore how the system's components work together, and find answers to common questions to help you navigate the platform effectively. +The MultiGov Staking Program on Solana is designed to be upgradeable while maintaining stability. Upgrades introduce improvements, bug fixes, and new features but must be carefully planned and executed to prevent disruptions. -## Get Started +This guide covers the key considerations and step-by-step process for upgrading the MultiGov Staking Program, including updating the program binary, Interface Description Language (IDL), and `HubProposalMetadata` while ensuring cross-chain compatibility. + +## Key Considerations for Upgrades + +- **Program upgradeability** - you can upgrade the MultiGov Staking Program on Solana using the `anchor upgrade` command + - You need the program's new bytecode (`.so` file) and an updated IDL file to reflect any changes in the program's interface to complete an upgrade + - The program's authority (deployer) must execute the upgrade -
+- **`HubProposalMetadata`** - can be updated without redeploying the entire program. You can do this by invoking the `updateHubProposalMetadata` instruction + - You must carefully validate updates to `HubProposalMetadata` to ensure compatibility with the existing system -- :octicons-book-16:{ .lg .middle } **Overview** +- **Cross-chain compatibility** - ensure any changes to the Solana program do not break compatibility with the Ethereum-based `HubGovernor` + - Test upgrades thoroughly on devnet before deploying to mainnet - --- +## Upgrade the MultiGov Program - Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. +Follow these steps to upgrade the MultiGov Staking Program on Solana: - [:custom-arrow: Take a first glance at MultiGov](/docs/learn/governance/overview/) +1. **Prepare the new program binary** - build the updated program using the provided script -- :octicons-book-16:{ .lg .middle } **Architecture** + ```bash + ./scripts/build_verifiable_staking_program.sh + ``` - --- + The new program binary will be located at: - Discover MultiGov's hub-and-spoke architecture, enabling EVM and Solana cross-chain governance through coordinated decision-making. + ```bash + target/deploy/staking.so + ``` - [:custom-arrow: Learn about MultiGov architecture](/docs/products/multigov/concepts/architecture/) +2. **Upgrade the program** - use the anchor upgrade command to deploy the new program binary -- :octicons-question-16:{ .lg .middle } **Theoretical FAQs** + ```bash + anchor upgrade --program-id INSERT_PROGRAM_ID --provider.cluster INSERT_CLUSTER_URL INSERT_PATH_TO_PROGRAM_BINARY + ``` - --- + Your completed anchor upgrade command should resemble the following: + ```bash + anchor upgrade --program-id DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY --provider.cluster https://api.devnet.solana.com ./target/deploy/staking.so + ``` - Find answers to common theoretical questions about MultiGov. +3. **Update the IDL** - after upgrading the program, update the IDL to reflect any changes in the program's interface - [:custom-arrow: Find the answer to your theoretical questions](/docs/products/multigov/faqs/) + ```bash + anchor idl upgrade INSERT_PROGRAM_ID --filepath INSERT_PATH_TO_IDL_FILE + ``` -
+ Your completed IDL upgrade command should resemble the following: + ```bash + anchor idl upgrade --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY + ``` -## Next Steps +4. **Update `HubProposalMetadata`** - if `HubProposalMetadata` requires an update, run the following script to invoke the `updateHubProposalMetadata` instruction and apply the changes -
+ ```bash + npx ts-node app/deploy/07_update_HubProposalMetadata.ts + ``` +--- END CONTENT --- -- :octicons-checklist-16:{ .lg .middle } **Begin the MultiGov Integration Process** +Doc-Content: https://wormhole.com/docs/products/multigov/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ +--- BEGIN CONTENT --- +--- +title: MultiGov Guides +description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. +categories: MultiGov +--- - Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. +# Cross-Chain treasury management proposal - [:custom-arrow: Start the integration process now](/docs/build/multigov/) +This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM Chains** +## Create a Proposal - --- +The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) +Key actions: -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** +- Define the proposal targets (two transactions to the Message Dispatcher) +- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) +- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum +- Finally, we submit the proposal to the `HubGovernor` contract - --- +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Prepare proposal details +address[] memory targets = new address[](2); +targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; +targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; +uint256[] memory values = new uint256[](2); +values[0] = 0; +values[1] = 0; +bytes[] memory calldatas = new bytes[](2); +// Prepare message for Optimism to mint 10 W tokens +// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) +calldatas[0] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + OPTIMISM_WORMHOLE_CHAIN_ID, + [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], + [uint256(10 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +// Prepare message for Arbitrum to receive 15 ETH +calldatas[1] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + ARBITRUM_WORMHOLE_CHAIN_ID, + [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], + [uint256(15 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; +// Create the proposal +uint256 proposalId = governor.propose( + targets, values, calldatas, description +) +``` - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. +??? interface "Parameters" - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) + `GOVERNOR_ADDRESS` ++"address"++ -- :octicons-code-square-16:{ .lg .middle } **Tutorials** + The address of the `HubGovernor` contract on Ethereum Mainnet. --- - Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. - - [:custom-arrow: Create MultiGov solutions](/docs/tutorials/multigov/) + `targets` ++"address[]"++ -- :octicons-question-16:{ .lg .middle } **Technical FAQs** + An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. --- - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) + `values` ++"uint256[]"++ -
---- END CONTENT --- + An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. -Doc-Content: https://wormhole.com/docs/learn/governance/overview/ ---- BEGIN CONTENT --- ---- -title: MultiGov Overview -description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -categories: MultiGov ---- + --- -# MultiGov: Cross-Chain Governance with Wormhole + `calldatas` ++"bytes[]"++ -## Overview + The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. -### What Is MultiGov and Why Is It Important? + --- -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. + `description` ++"string"++ -MultiGov is important because it: + A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. -- **Increases participation** by allowing token holders from multiple chains to engage in governance -- **Enhances security** by leveraging Wormhole's robust cross-chain communication -- **Improves scalability** by integrating any chain supported by Wormhole -- **Enables unified governance** and coordinated decision-making across multiple networks +??? interface "Returns" -### Key Features + `proposalId` ++"uint256"++ -- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains -- **Cross-chain voting** - token holders on any integrated chain can cast votes -- **Vote aggregation** - votes from all chains are collected and tallied on the hub -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Wormhole integration** - secure and reliable cross-chain communication -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain + The ID of the newly created proposal on the hub chain. -### High-Level Architecture Diagram +## Vote on the Proposal via Spoke -The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. +Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. +Key actions: - -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/learn/governance/multigov-high-level.webp) ---- END CONTENT --- +- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain +- Cast a vote in support of the proposal -Doc-Content: https://wormhole.com/docs/learn/ ---- BEGIN CONTENT --- ---- -title: Learn about Wormhole -description: Learn the basics of Wormhole, covering its architecture, messaging protocols, and how it enables multichain communication and asset transfers. -template: root-index-page.html ---- +```solidity +// Connect to the SpokeVoteAggregator contract of the desired chain +SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); +// Cast a vote +uint8 support = 1; // 1 for supporting, 0 for opposing +uint256 weight = voteAggregator.castVote(proposalId, support); +``` -# Learn +??? interface "Parameters" -These informational sections will help you get to know Wormhole. Start with the fundamentals, then discover Wormhole's multichain transfer products and governance system. + `VOTE_AGGREGATOR_ADDRESS` ++"address"++ -## Fundamentals + The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). -To understand Wormhole from the ground up, visit the following sections. + --- -
+ `proposalId` ++"uint256"++ -- :octicons-book-16:{ .lg .middle } **Introduction to Wormhole** + The ID of the proposal created on the hub chain, which is being voted on. --- - Learn more about the problems Wormhole solves, explore use cases, and view a list of supported blockchains. + `support` ++"uint8"++ - [:custom-arrow: Introduction to Wormhole](/docs/protocol/introduction/) + The vote being cast (`1` for supporting the proposal, `0` for opposing). -- :octicons-book-16:{ .lg .middle } **Messaging Infrastructure** +??? interface "Returns" - --- + `weight` ++"uint256"++ - Investigate the messaging protocol architecture with an in-depth exploration of the individual components powering Wormhole's infrastructure. + The weight of the vote, determined by the voter’s token holdings on the spoke chain. - [:custom-arrow: Understand Wormhole's infrastructure](/docs/protocol/infrastructure/) +## Vote Aggregation -
+In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. -## Multichain Transfers +Key actions: -Wormhole transfer products offer multiple options to meet your project's needs. Which product is best for your use depends upon the asset transfer type you want to add to your dApp. +- Aggregate votes from different chains and submit them to the hub chain for tallying -### Wrapped Tokens +```solidity +// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) +hubVotePool.crossChainVote(queryResponseRaw, signatures); +``` -This method is likely familiar to you if you've previously built bridging projects. +??? interface "Parameters" -
+ `queryResponseRaw` ++"bytes"++ -- :octicons-book-16:{ .lg .middle } **Token Bridge** + The raw vote data from the spoke chains. --- - - Use Wormhole deployed contracts to simplify development - - Multichain token transfers through lock-and-mint-mechanism - - Option to include message payload for uses like social platforms - - [:custom-arrow: Learn about Token Bridge](/docs/learn/transfers/token-bridge/) - -
+ `signatures` ++"bytes"++ -### Native Tokens + Cryptographic signatures that verify the validity of the votes from the spoke chains. -Eliminate wrapped assets to preserve your token's native properties across chains. +## Execute Proposal and Dispatch Cross-Chain Messages -
+After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. -- :octicons-book-16:{ .lg .middle } **Native Token Transfers** +Key actions: - --- +- Execute the proposal after the voting period ends and the proposal passes +- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. - - Deploy custom smart contracts to retain token ownership and upgrade authority with complete customizability - - No wrapped tokens or liquidity pools to avoid slippage and MEV risk - - Custom attestation is available by adding external verifiers +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Standard timelock execution +governor.execute(targets, values, calldatas, descriptionHash); +``` - [:custom-arrow: Learn about Native Token Transfers](/docs/learn/transfers/native-token-transfers/) +??? interface "Parameters" -
+ `governor` ++"HubGovernor"++ -### Intent-Based Transfers + The `HubGovernor` contract instance. -Institutional-scale digital asset settlement for individual users and insitutions. + --- -
+ `targets` ++"address[]"++ -- :octicons-book-16:{ .lg .middle } **Settlement** + An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). --- - - Leverages three protocols, providing flexibility and redundancy - - Chain-agnostic to liquidity on chains, enabling broader chain support - - English auction determines the winning solver for settlement - - USDC as the shuttle asset for seamless cross-chain settlement + `values` ++"uint256[]"++ + + An array of values (in Wei) associated with each transaction (both are zero in this case). - [:custom-arrow: Learn about Settlement](/docs/learn/transfers/settlement/) + --- -
+ `calldatas` ++"bytes[]"++ -## Governance + The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). -Explore MultiGov, Wormhole's multichain governance solution. + --- -
+ `descriptionHash` ++"bytes32"++ -- :octicons-book-16:{ .lg .middle } **Multichain Governance** + A hash of the proposal’s description, used to verify the proposal before execution. - --- +??? interface "Returns" - - Multichain voting and proposal execution - - Aggregates votes from all chains - - Can integrate with any Wormhole-supported blockchain + No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. - [:custom-arrow: Learn about MultiGov](/docs/learn/governance/) +Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Architecture +description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +categories: NTT, Transfer +--- -## Additional Resources +## Introduction -
+The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. -- :octicons-book-16:{ .lg .middle } **Product Comparison** - --- +## System Components - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. + +### Managers - [:custom-arrow: Compare Products](/docs/build/start-building/products/){target=\_blank} +_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. -- :octicons-book-16:{ .lg .middle } **Use Cases** +Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. - --- +A manager is responsible for: - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer +- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers + - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted + - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) + Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit -
---- END CONTENT --- +- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed +- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility -Doc-Content: https://wormhole.com/docs/protocol/architecture/ ---- BEGIN CONTENT --- ---- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. -categories: Basics ---- +### Transceivers -# Architecture +_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. -## Overview +While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +Transceivers are entrusted with several responsibilities: -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing +- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer +- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +How it works: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +1. The transceiver receives instructions from the manager to send messages across chains +2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred +3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +!!! note + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. -## On-Chain Components +#### Custom Transceivers -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. -## Off-Chain Components +NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) -## Next Steps +The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. -
+For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. -- :octicons-book-16:{ .lg .middle } **Core Contracts** +## Lifecycle of a Message - --- +The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +### Transfer - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. -- :octicons-tools-16:{ .lg .middle } **Core Messaging** +In both cases: - --- +- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain +- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain - Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +### Rate Limit -
---- END CONTENT --- +Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- +- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error +- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error -# Core Contracts +Both chains emit events or logs when transfers are rate-limited or queued. -## Introduction +### Send -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. +After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. +- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message +- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification -## Key Functions +In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. -Key functions of the Wormhole Core Contract include the following: +### Receive -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time +Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. -## How the Core Contract Works +- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers +- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. +In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. -The following describes the role of the Wormhole Core Contract in message transfers: +### Mint or Unlock -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions +Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. +- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred +- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced -### Message Submission +In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. +--- END CONTENT --- -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/security/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Security +description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. +categories: NTT, Transfer +--- -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page +# Security -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. +## Global Accountant -### Message Reception +The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. +This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. -## Multicast +[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. +## Governance and Upgradeability -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. +Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. +- Adding or removing a transceiver address from the registry +- Setting the token contract address on a bridging contract +- Setting the Wormhole Core Contract address on a bridging contract +- Setting the registered bridging contract address on the token contract -## Next Steps +This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Access Control +description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +categories: NTT, Transfer +--- -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** +## Owner and Pauser Roles - --- +Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. +NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) +- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused +- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** +You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. - --- +```json +{ + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": true, // set to true to pause the contract + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + //... + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } +} +``` - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. +!!! note + While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) +The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. -
+Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ --- BEGIN CONTENT --- --- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics +title: Native Token Transfers Rate Limiting +description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. +categories: NTT, Transfer --- -## Guardian +## Introduction -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. -Guardians fulfill their role in the messaging protocol as follows: +If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state +You can configure the following limits on every chain where NTT is deployed directly using the manager: -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). +- **Sending limit** - a single outbound limit for sending tokens from the chain +- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum -## Guardian Network +Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. +## Update Rate Limits -The Guardian Network is designed to help Wormhole deliver on five key principles: +To configure or update the sending and receiving rate limits, follow these steps: -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing +1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts + +2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed + + ```json + "limits": { + "outbound": "1000.000000000000000000", + "inbound": { + "Ethereum": "100.000000000000000000", + "Arbitrum": "50.000000000000000000" + } + } + ``` + + - **`outbound`** - sets the maximum tokens allowed to leave the chain + - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains -The following sections explore each principle in detail. +3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain -### Decentralization + ```bash + ntt push + ``` -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. +4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status -Two common approaches to decentralization have notable limitations: + ```bash + ntt status + ``` -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment +???- note "`deployment.json` example" + ```json + { + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": false, + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", + "transceivers": { + "threshold": 1, + "wormhole": { + "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + }, + "limits": { + "outbound": "184467440737.095516150000000000", + "inbound": { + "ArbitrumSepolia": "500.000000000000000000" + } + }, + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } + } + ``` -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. +## Queuing Mechanism -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? +When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: -To answer that, consider these key constraints and design decisions: +- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer +- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants +Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. +## Cancel Flows -### Modularity +If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. +--- END CONTENT --- -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers FAQs +description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +categories: NTT, Transfer +--- -### Chain Agnosticism +# Wormhole NTT FAQs -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. +## Do you have an example of how cross-chain lending can be implemented using Wormhole? -### Scalability +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. +Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. +## What causes the "No protocols registered for Evm" error in Wormhole SDK? -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. +This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. -### Upgradeable +To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: -Wormhole is designed to adapt and evolve in the following ways: +```rust +import '@wormhole-foundation/sdk-evm-ntt'; +``` -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model +By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## How can I transfer ownership of NTT to a multisig? -## Next Steps +Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. -
+1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) +2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer +3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) -- :octicons-book-16:{ .lg .middle } **Relayers** +For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. - --- +## How can I specify a custom RPC for NTT? - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) +Below’s an example of how the `overrides.json` file should be structured: -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** +???- code "`overrides.json`" + ```json + { + "chains": { + "Bsc": { + "rpc": "http://127.0.0.1:8545" + }, + "Sepolia": { + "rpc": "http://127.0.0.1:8546" + }, + "Solana": { + "rpc": "http://127.0.0.1:8899" + } + } + } + ``` - --- +## How can I redeem tokens if NTT rate limits block them on the target chain? - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. +If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) +To resolve this: -
---- END CONTENT --- +1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed +2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/ ---- BEGIN CONTENT --- ---- -title: Infrastructure Components -description: Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. -categories: Basics ---- +In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. + +## What are the challenges of deploying NTT to non-EVM chains? -# Infrastructure Components +NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. -This section examines the core components that power Wormhole's infrastructure, including Guardians, relayers, VAAs, and the Spy. +## Does the NTT manager function as an escrow account for a hub chain? -## Get Started +Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. -Start here for an overview of Wormhole architecture components and security mechanisms: +## Which functions or events does Connect rely on for NTT integration? -
+Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: -- :octicons-book-16:{ .lg .middle } **Architecture Overview** +- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain +- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion - --- +These functions ensure Connect can handle token transfers and manage chain-rate limits. - Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +## How does the relayer contract determine which transceiver to call? - [:custom-arrow: Learn About Architecture](/docs/protocol/architecture/) +The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. -- :octicons-book-16:{ .lg .middle } **Security** +## How do I create a verifier or transceiver? - --- +To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. - Explore Wormhole's security features, including the Guardian network, governance, and monitoring. +For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. - [:custom-arrow: Learn About Security](/docs/protocol/security/) +## Can I use Hetzner for the NTT deployment? -
+No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. -## Explore Components +## How can I transfer tokens with NTT with an additional payload? -The relationship between individual components can be demonstrated through the simplified flow of a multichain message from a source-chain contract to a target-chain contract. Select the title of each step to learn more about that component: +You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. -[timeline left(wormhole-docs/.snippets/text/protocol/infrastructure/infrastructure-index-timeline.json)] +- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message +- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message -The [Spy](/docs/protocol/infrastructure/spy/) continuously runs in the background to subscribe to gossiped messages across the Guardian Network and enable real-time network activity monitoring. +!!!Important + You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. -## Next Steps +## Why use NTT over xERC20? -
+Shortcomings of xERC20: -- :octicons-book-16:{ .lg .middle } **Messaging Components** +- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach +- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies +- **No access control** - there are no built-in access controls for managing token transfers securely +- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security +- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups - --- +While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. - Learn more about individual messaging components such as Core Contracts, VAAs, Guardians, and relayers +## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. -- :octicons-people-16:{ .lg .middle } **Core Messaging Guides** +## Is there a way to use NTT tokens with chains that don't currently support NTT? - --- +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: - Explore this section for guides to using Wormhole Relayer and Core Contracts in your project. +- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) +- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism +- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT - [:custom-arrow: Build with Core Messaging](/docs/build/core-messaging/) +This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ +--- BEGIN CONTENT --- +TODO --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -categories: Basics +title: Native Token Transfers EVM Deployment +description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer --- -# Relayers +# Native Token Transfers (NTT) EVM Development -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. +## Deploy Your Token and Ensure Compatibility -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. +If you still need to do so, deploy the token contract to the destination or spoke chains. -There are three primary types of relayers discussed: +### Requirements for Token Deployment -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved +Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) +#### Burn-and-Mint Mode -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient +Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: -## Fundamentals +- `burn(uint256 amount)` +- `mint(address account, uint256 amount)` -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. +These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. +??? code "View the complete `INttToken` Interface`" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; -Key characteristics of VAAs include: +interface INttToken { + /// @notice Error when the caller is not the minter. + /// @dev Selector 0x5fb5729e. + /// @param caller The caller of the function. + error CallerNotMinter(address caller); -- Public emission from the Guardian Network + /// @notice Error when the minter is the zero address. + /// @dev Selector 0x04a208c7. + error InvalidMinterZeroAddress(); -- Authentication through signatures from the Guardian Network + /// @notice Error when insufficient balance to burn the amount. + /// @dev Selector 0xcf479181. + /// @param balance The balance of the account. + /// @param amount The amount to burn. + error InsufficientBalance(uint256 balance, uint256 amount); -- Verifiability by any entity or any Wormhole Core Contract + /// @notice The minter has been changed. + /// @dev Topic0 + /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. + /// @param newMinter The new minter. + event NewMinter(address previousMinter, address newMinter); -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. + // NOTE: the `mint` method is not present in the standard ERC20 interface. + function mint(address account, uint256 amount) external; -Keep in mind the following security considerations around relayers: + // NOTE: the `setMinter` method is not present in the standard ERC20 interface. + function setMinter(address newMinter) external; + + // NOTE: NttTokens in `burn` mode require the `burn` method to be present. + // This method is not present in the standard ERC20 interface, but is + // found in the `ERC20Burnable` interface. + function burn(uint256 amount) external; +} + ``` -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks +Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly +#### Hub-and-Spoke Mode -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain +A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. -## Client-Side Relaying + - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains + - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. +!!! note + The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. -### Key Features +For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs +This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure +For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. -### Implementation +### Key Differences Between Modes -Users themselves carry out the three steps of the cross-chain process: + - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently + - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency -1. Perform an action on chain A +## Deploy NTT -2. Retrieve the resulting VAA from the Guardian Network +Create a new NTT project: -3. Perform an action on chain B using the VAA +```bash +ntt new my-ntt-deployment +cd my-ntt-deployment +``` -### Considerations +Initialize a new `deployment.json` file specifying the network: -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. +=== "Testnet" -- Users must sign all required transactions with their own wallet + ```bash + ntt init Testnet + ``` -- Users must have funds to pay the transaction fees on every chain involved +=== "Mainnet" -- The user experience may be cumbersome due to the manual steps involved + ```bash + ntt init Mainnet + ``` -## Custom Relayers +Ensure you have set up your environment correctly: -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. +```bash +export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY +``` -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). +Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: -### Key Features +```bash +# Set scanner API Keys as environment variables +export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY +export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs +# Add each chain +# The contracts will be automatically verified using the scanner API keys above +ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +``` -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more +While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application +The `ntt add-chain` command takes the following parameters: -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience +- Name of each chain +- Version of NTT to deploy (use `--latest` for the latest contract versions) +- Mode (either `burning` or `locking`) +- Your token contract address -### Implementation +The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. +## Configure NTT -### Considerations +The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." +- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain +- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: -- Development work and hosting of relayers are required + For Solana, the limits are set with 9 decimal places: + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + } + ``` -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees + For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: + ```json + "inbound": { + "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia + } + ``` -- Relayers are responsible for availability, and adding dependencies for the cross-chain application + This initial configuration ensures that the rate limits are correctly represented for each chain's token precision + +- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file -## Wormhole Relayers +After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. +## Set Token Minter to NTT Manager -### Key Features +The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. -- **Lower operational costs** - no need to develop, host, or maintain individual relayers +!!! note + The required NTT Manager address can be found in the `deployment.json` file. -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface +- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function + ```json + cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + ``` -### Implementation +- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter -The Wormhole relayer integration involves two key steps: +By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract +!!!important + To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. +--- END CONTENT --- -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Solana Deployment +description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- -### Considerations +# Deploy Native Token Transfers on Solana -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -- All computations are performed on-chain +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. -- Potentially less gas-efficient compared to custom relayers +By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted +## Prerequisites -- Support may not be available for all chains +Before deploying NTT on Solana, ensure you have the following: -## Next Steps +- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} +- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** +- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -
+Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. -- :octicons-book-16:{ .lg .middle } **Spy** +## Overview of the Deployment Process - --- +Deploying NTT with the CLI on Solana follows a structured process: - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +1. **Choose your token setup**: - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) + - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section + - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** + ???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. - --- + 1. **Generate a Solana key pair** - run the following command to create a new wallet: - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` - --- + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. + === "Mainnet" + ```bash + solana config set -um + ``` - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) + === "Testnet" + ```bash + solana config set -ut + ``` -
---- END CONTENT --- + === "Devnet" + ```bash + solana config set -ud + ``` -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: -# Spy + ```bash + solana airdrop 2 + solana balance + ``` -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. + ```bash + cargo install spl-token-cli + ``` -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. + 6. **Create a new SPL token** - initialize the token on Solana -## Key Features + ```bash + spl-token create-token + ``` -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure + 7. **Create a token account** - generate an account to hold the token -## Integrator Use Case + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. + 8. **Mint tokens** - send 1000 tokens to the created account -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` -## Observable Message Categories + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -A Spy can access the following categories of messages shared over the gossip protocol: +2. **Choose your [deployment model](TODO){target=\_blank}**: -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification +3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +## Set Up NTT - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network +To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -## Additional Resources +The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: -
+1. **Create a new NTT project** - set up a deployment workspace -- :octicons-code-16:{ .lg .middle } **Spy Source Code** + ```bash + ntt new INSERT_PROJECT_NAME + cd INSERT_PROJECT_NAME + ``` - --- +2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. + === "Mainnet" - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} + ```bash + ntt init Mainnet + ``` -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** + === "Testnet" - --- + ```bash + ntt init Testnet + ``` +!!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. +### Set Mint Authority - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) +If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** +If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). - --- +Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. +Follow these steps to set the mint authority using the NTT CLI: - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) +1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment -
+ ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` -## Next Steps +2. **Derive the token authority** - generate the PDA, which will manage token minting -
+ ```bash + ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR + ``` -- :octicons-code-16:{ .lg .middle } **Run a Spy** +3. **Set SPL token mint authority** - delegate minting control to the derived PDA - --- + ```bash + spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA + ``` - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). +## Deploy and Configure NTT - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} +After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: -- :octicons-code-16:{ .lg .middle } **Use Queries** +1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: - --- + === "Burn-and-Mint" - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. + ```bash + ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + === "Hub-and-Spoke" -
---- END CONTENT --- + ```bash + ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- + !!! tip + The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. -# Verified Action Approvals +2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. + ```bash + ntt status + ``` -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. + If needed, sync your local configuration with the on-chain state: -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. + ```bash + ntt pull + ``` -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. +3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. + Open your `deployment.json` file and adjust the values based on your use case: -## VAA Format + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + }, + "outbound": { + "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia + } + ``` -The basic VAA consists of header and body components described as follows: +4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures + ```bash + ntt push --payer INSERT_YOUR_KEYPAIR_JSON + ``` - Where each `signature` is: +### Troubleshoot Deployment Issues + +If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature +## Where to Go Next -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on +
-The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level +- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. + --- -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. + After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. -## Consistency and Finality + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. +- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. + --- -## Signatures + Follow the NTT Post Deployment Guide for integration examples and testing instructions. -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` +- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. + --- -## Payload Types + Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} -### Token Transfer +
+--- END CONTENT --- -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +--- BEGIN CONTENT --- +--- +title: Deploy Native Token Transfers with Launchpad +description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +categories: NTT, Transfer +--- -Transferring tokens from the sending chain to the destination chain requires the following steps: +# Deploy Native Token Transfers with Launchpad -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain +## Introduction -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: +The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer +Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. +The Launchpad automates deployment, reducing complexity and saving time. -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. +This guide covers: -### Attestation + - Launching a new cross-chain token + - Expanding an existing token for NTT + - Managing tokens via the dashboard and settings -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. +## Prerequisites -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. + - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) + - Minimum ETH (or equivalent) for gas fees per deployment -The message format for token attestation is as follows: +## Supported Blockchains -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset +The NTT Launchpad currently supports deployments on the following mainnet chains: -#### Attestation Tips + - Ethereum + - Arbitrum One + - Base + - Berachain + - Blast + - BNB Smart Chain + - Ink + - Optimism Mainnet + - Polygon -Be aware of the following considerations when working with attestations: +## Choose Your Path -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters +Once ready, choose an option to proceed: -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains + - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm +## Launch a Cross-Chain Token -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 +Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** -### Token Transfer with Message + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Launch a Cross-Chain Token** -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior +3. Set the token details: + 1. Select the **home network** from the dropdown menu + 2. Enter the **name** for the token + 3. Enter the **symbol** of the token + 4. Provide the **initial supply** + 5. To the token details, click **Next** -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific +4. Select the deployment chains: + 1. The home network where your token will be deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** -### Governance + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction -#### Action Structure + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` +8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. -#### Actions +## Expand Your Existing Token -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: +Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** -## Lifetime of a Message + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. +2. Select **Expand Your Existing Token** -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step +3. Enter the token details: + 1. Choose the home network where your token is already deployed (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) -## Next Steps +4. Select the chains to deploy your token to: + 1. The home network where your token is already deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 1. Click **Next** -
+ ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) -- :octicons-book-16:{ .lg .middle } **Guardians** +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - --- + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step - --- +8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. +## Explore the Launchpad Dashboard - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) +To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -
---- END CONTENT --- +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) -Doc-Content: https://wormhole.com/docs/protocol/introduction/ ---- BEGIN CONTENT --- ---- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics ---- +The dashboard provides a high-level view of your token across all deployed chains, including: -# Introduction to Wormhole + - Token addresses for each chain + - Supply distribution visualization + - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +## Settings -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +### Chain Management -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +From this section, you can also: -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. + - **Pause the token** – temporarily turn off transfers on the selected chain + - **Deploy to a new chain** – expand your token by deploying it to an additional chain -## What Problems Does Wormhole Solve? +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +### Role Management -Critical problems Wormhole addresses include: +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions + - **Manager’s Owner** – the owner through the `NTTOwner` proxy + - **Pauser** – the address authorized to pause transfers -## What Does Wormhole Offer? +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +### Security Threshold -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. -## What Isn't Wormhole? +A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge + - **Registered Transceivers** – displays the number of registered transceivers and their addresses + - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -## Use Cases of Wormhole +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) -Consider the following examples of potential applications enabled by Wormhole: +### Peer Chains Limits -- **Cross-chain exchange** - using [Wormhole Connect](/docs/build/transfers/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +Define the transfer restrictions for each connected network. You can adjust: -## Explore + - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain + - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains -Discover more about the Wormhole ecosystem, components, and protocols: +Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) +--- END CONTENT --- -## Demos +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -Demos offer more realistic implementations than tutorials: +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +--- BEGIN CONTENT --- +--- +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer +--- -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +# NTT CLI Commands - +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -!!! note - Wormhole Integration Complete? +If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +## Table of Commands - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +The following table lists the available NTT CLI commands, descriptions, and examples. -## Supported Blockchains +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. -Wormhole supports a growing number of blockchains. +### General Commands - - -
+| Command | Description | Examples | +|-----------------------------------------|-------------------------------------------------------|--------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| +| `ntt clone
` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | -### EVM +### Configuration Commands -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Command | Description | Examples | +|---------------------------------------------|----------------------------------------|-------------------------------------| +| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| +| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| -### SVM +### Solana Commands -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Command | Description | Examples | +|-----------------------------------------------|---------------------------------------------------------|------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| +| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| +| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| -### AVM +## Where to Go Next -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
-### CosmWasm -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-gear-16:{ .lg .middle } **Configure NTT** -### Move VM + --- -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -### NEAR VM + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -### Sui Move VM + --- + + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. + + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics +title: Troubleshooting NTT Deployment +description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +categories: NTT, Transfer --- -# Security - -## Core Security Assumptions - -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +# Troubleshooting NTT Deployment -In summary: +If you encounter issues during the NTT deployment process, check the following common points: -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} + - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** + - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain +- **Mint authority transfer** + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} +- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. + ???- interface "Dockerfile" -## Guardian Network + ```Dockerfile + FROM ubuntu:20.04 + # Set environment variables to prevent interactive prompts during installation + ENV DEBIAN_FRONTEND=noninteractive -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. + # Update and install necessary dependencies + RUN apt-get update && apt-get install -y \ + curl \ + wget \ + git \ + build-essential \ + libssl-dev \ + libudev-dev \ + pkg-config \ + python3 \ + python3-pip \ + software-properties-common \ + ca-certificates \ + unzip \ + clang \ + cmake \ + protobuf-compiler \ + && apt-get clean && rm -rf /var/lib/apt/lists/* -### Governance + # Install Rust + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + ENV PATH="/root/.cargo/bin:$PATH" -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. + # Install Solana CLI ({{ntt.solana_cli_version}}) + RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" + ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. + # Install Anchor using avm + RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ + && avm install 0.29.0 \ + && avm use 0.29.0 + ENV PATH="/root/.avm/bin:$PATH" -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. + ENV NVM_DIR=/root/.nvm + RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ + && . "$NVM_DIR/nvm.sh" \ + && nvm install 22 \ + && nvm use 22 \ + && nvm alias default 22 + ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" -Via governance, the Guardians can: + # Install Bun + RUN curl -fsSL https://bun.sh/install | bash + ENV PATH="/root/.bun/bin:$PATH" -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations + # Install Foundry + RUN curl -L https://foundry.paradigm.xyz | bash + ENV PATH="/root/.foundry/bin:${PATH}" + RUN /bin/bash -c "source /root/.bashrc && foundryup" -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. + # Install Wormhole NTT CLI + RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash -## Monitoring + # Add a default working directory + WORKDIR /app -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. + # Expose port for development if needed + EXPOSE 8899 -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. + # Entry point for the container + CMD ["bash"] + ``` -Guardians monitor: + ???- interface "docker-compose.yml" + ```yml + services: + portal-ntt: + build: + context: . + dockerfile: Dockerfile + platform: linux/amd64 + volumes: + - ./src:/app + working_dir: /app + tty: true + ``` +--- END CONTENT --- -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +Doc-Content: https://wormhole.com/docs/products/products/ +--- BEGIN CONTENT --- +--- +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics +--- -## Asset Layer Protections +# Products -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -## Open Source +## Transfer Products -Wormhole builds in the open and is always open source. +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -## Audits +
-Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +::spantable:: -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +| | Criteria | Connect | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | | +| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | +| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | +| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. +::end-spantable:: -## Bug Bounties +
-Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## Real-time Data -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +## Multichain Governance -## Learn More +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. +--- END CONTENT --- -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +Doc-Content: https://wormhole.com/docs/products/queries/concepts/rpc-basics/ +--- BEGIN CONTENT --- +TODO --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/cctp/ +Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- -title: Circle's CCTP Bridge -description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -categories: Transfer +title: Queries FAQs +description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. +categories: Queries --- -# Circle's CCTP Bridge - -Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. +# Wormhole Queries FAQs -While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: +## What libraries are available to handle queries? -- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves -- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain -- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer + - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses -!!! note - Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. +- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. +- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests -## Automatic Relaying +- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses -To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. +!!! note + A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/build/transfers/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. +## Are there any query examples? -The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. +Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: -| Chain | Fee | -|:---------------:|:---------------:| -| Ethereum | 1.0 USDC | -| Everything else | 0.1 USDC | +- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} +- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} +- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} +- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} - +## What is the format of the response signature? -## Native Gas Drop Off +The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: -Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. +```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` -The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. +See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. - ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/ ---- BEGIN CONTENT --- ---- -title: Multichain Transfers -description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -categories: Transfer ---- - -# Multichain Transfers - -These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. + If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. -Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: +## Can anyone run a query proxy server? -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset -- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism +Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. -## Compare Transfer Products +It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. -A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: +## What Does Queries Offer over an RPC Service -### NTT vs. Token Bridge +Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. +--- END CONTENT --- -Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. +Doc-Content: https://wormhole.com/docs/products/queries/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains -- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases +Doc-Content: https://wormhole.com/docs/products/queries/guides/construct-a-query/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/queries/guides/mock-a-query/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -| Supports | NTT | Token Bridge | -|---------------------------|--------------------|--------------------| -| Message Payload | :white_check_mark: | :white_check_mark: | -| Wrapped Assets | :x: | :white_check_mark: | -| Native Assets | :white_check_mark: | :x: | -| Contract-Free Development | :x: | :white_check_mark: | -| User-Owned Contracts | :white_check_mark: | :x: | +Doc-Content: https://wormhole.com/docs/products/queries/guides/query-request/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/queries/guides/submit-response/ +--- BEGIN CONTENT --- -In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/queries/guides/verify-response/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/queries/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -### Settlement +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-networks/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ +--- BEGIN CONTENT --- +--- +title: Chain IDs +description: This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. +categories: Reference +--- -## Additional Resources +# Chain IDs -
+The following table documents the chain IDs used by Wormhole and places them alongside the more commonly referenced [EVM Chain IDs](https://chainlist.org/){target=\_blank}. -- :octicons-tools-16:{ .lg .middle } **Product Comparison** +!!! note + Please note, Wormhole chain IDs are different than the more commonly referenced EVM [chain IDs](https://eips.ethereum.org/EIPS/eip-155){target=\_blank}, specified in the Mainnet and Testnet ID columns. - --- + + - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +=== "Mainnet" - [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) + | Ethereum | 2 | 1 | +| Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | +| Acala | 12 | 787 | +| Algorand | 8 | mainnet-v1.0 | +| Aptos | 22 | 1 | +| Arbitrum | 23 | Arbitrum One-42161 | +| Avalanche | 6 | C-Chain-43114 | +| Base | 30 | Base-8453 | +| Berachain | 39 | | +| Blast | 36 | 81457 | +| BNB Smart Chain | 4 | 56 | +| Celestia | 4004 | celestia | +| Celo | 14 | 42220 | +| Cosmos Hub | 4000 | cosmoshub-4 | +| Dymension | 4007 | dymension_1100-1 | +| Evmos | 4001 | evmos_9001-2 | +| Fantom | 10 | 250 | +| Gnosis | 25 | 100 | +| HyperEVM | 47 | | +| Injective | 19 | injective-1 | +| Ink | 46 | | +| Kaia | 13 | 8217 | +| Karura | 11 | 686 | +| Kujira | 4002 | kaiyo-1 | +| Linea | 38 | 59144 | +| Mantle | 35 | 5000 | +| Mezo | 50 | | +| Monad | 48 | | +| Moonbeam | 16 | 1284 | +| NEAR | 15 | mainnet | +| Neon | 17 | 245022934 | +| Neutron | 4003 | neutron-1 | +| Noble | 4009 | noble-1 | +| Oasis | 7 | 42262 | +| Optimism | 24 | 10 | +| Osmosis | 20 | osmosis-1 | +| Polygon | 5 | 137 | +| Provenance | 4008 | pio-mainnet-1 | +| Pythnet | 26 | | +| Scroll | 34 | 534352 | +| SEDA | 4006 | | +| Sei | 32 | pacific-1 | +| Seievm | 40 | | +| SNAXchain | 43 | 2192 | +| Stargaze | 4005 | stargaze-1 | +| Sui | 21 | 35834a8a | +| Terra | 3 | columbus-5 | +| Terra 2.0 | 18 | phoenix-1 | +| Unichain | 44 | | +| World Chain | 45 | 480 | +| X Layer | 37 | 196 | +| XPLA | 28 | dimension_37-1 | -- :octicons-book-16:{ .lg .middle } **Use Cases** +=== "Testnet" - --- + | Ethereum Holesky | 10006 | Holesky-17000 | +| Ethereum Sepolia | 10002 | Sepolia-11155111 | +| Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | +| Acala | 12 | 597 | +| Algorand | 8 | testnet-v1.0 | +| Aptos | 22 | 2 | +| Arbitrum Sepolia | 10003 | Sepolia-421614 | +| Avalanche | 6 | Fuji-43113 | +| Base Sepolia | 10004 | Base Sepolia-84532 | +| Berachain | 39 | 80084 | +| Blast | 36 | 168587773 | +| BNB Smart Chain | 4 | 97 | +| Celestia | 4004 | mocha-4 | +| Celo | 14 | Alfajores-44787 | +| Cosmos Hub | 4000 | theta-testnet-001 | +| Dymension | 4007 | | +| Evmos | 4001 | evmos_9000-4 | +| Fantom | 10 | 4002 | +| Gnosis | 25 | Chiado-10200 | +| HyperEVM | 47 | 998 | +| Injective | 19 | injective-888 | +| Ink | 46 | 763373 | +| Kaia | 13 | Kairos-1001 | +| Karura | 11 | 596 | +| Kujira | 4002 | harpoon-4 | +| Linea | 38 | 59141 | +| Mantle | 35 | Sepolia-5003 | +| Mezo | 50 | 31611 | +| Monad | 48 | 10143 | +| Moonbeam | 16 | Moonbase-Alphanet-1287 | +| NEAR | 15 | testnet | +| Neon | 17 | 245022940 | +| Neutron | 4003 | pion-1 | +| Noble | 4009 | grand-1 | +| Oasis | 7 | 42261 | +| Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | +| Osmosis | 20 | osmo-test-5 | +| Polygon Amoy | 10007 | Amoy-80002 | +| Provenance | 4008 | | +| Pythnet | 26 | | +| Scroll | 34 | Sepolia-534351 | +| SEDA | 4006 | seda-1-testnet | +| Sei | 32 | atlantic-2 | +| Seievm | 40 | | +| SNAXchain | 43 | 13001 | +| Stargaze | 4005 | | +| Sui | 21 | 4c78adac | +| Terra | 3 | bombay-12 | +| Terra 2.0 | 18 | pisco-1 | +| Unichain | 44 | Unichain Sepolia-1301 | +| World Chain | 45 | 4801 | +| X Layer | 37 | 195 | +| XPLA | 28 | cube_47-5 | + +--- END CONTENT --- - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ +--- BEGIN CONTENT --- +--- +title: Wormhole Finality | Consistency Levels +description: This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. +categories: Reference +--- - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) +# Wormhole Finality +The following table documents each chain's `consistencyLevel` values (i.e., finality reached before signing). The consistency level defines how long the Guardians should wait before signing a VAA. The finalization time depends on the specific chain's consensus mechanism. The consistency level is a `u8`, so any single byte may be used. However, a small subset has particular meanings. If the `consistencyLevel` isn't one of those specific values, the `Otherwise` column describes how it's interpreted. -
+ + +| Ethereum | 200 | 201 | | finalized | ~ 19min | Details | +| Solana | | 0 | 1 | | ~ 14s | Details | +| Acala | 200 | 201 | | finalized | ~ 24s | | +| Algorand | | | 0 | | ~ 4s | Details | +| Aptos | | | 0 | | ~ 4s | Details | +| Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | +| Avalanche | 200 | | | finalized | ~ 2s | Details | +| Base | 200 | 201 | | finalized | ~ 18min | | +| Berachain | 200 | | | finalized | ~ 4s | | +| Blast | 200 | 201 | | finalized | ~ 18min | | +| BNB Smart Chain | 200 | 201 | | finalized | ~ 48s | Details | +| Celestia | | | 0 | | ~ 5s | | +| Celo | 200 | | | finalized | ~ 10s | | +| Cosmos Hub | | | 0 | | ~ 5s | | +| Dymension | | | 0 | | ~ 5s | | +| Evmos | | | 0 | | ~ 2s | | +| Fantom | 200 | | | finalized | ~ 5s | | +| Injective | | | 0 | | ~ 3s | | +| Ink | | | 0 | | ~ 9min | | +| Kaia | 200 | | | finalized | ~ 1s | | +| Karura | 200 | 201 | | finalized | ~ 24s | Details | +| Kujira | | | 0 | | ~ 3s | | +| Mantle | 200 | 201 | | finalized | ~ 18min | | +| Mezo | | | 0 | | ~ 8s | | +| Monad | | | 0 | | ~ 2s | | +| Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | +| NEAR | | | 0 | | ~ 2s | Details | +| Neutron | | | 0 | | ~ 5s | | +| Oasis | 200 | | | finalized | ~ 12s | | +| Optimism | 200 | 201 | | finalized | ~ 18min | | +| Osmosis | | | 0 | | ~ 6s | | +| Polygon | 200 | | | finalized | ~ 66s | Details | +| Scroll | 200 | | | finalized | ~ 16min | | +| Sei | | | 0 | | ~ 1s | | +| Stargaze | | | 0 | | ~ 5s | | +| Sui | | | 0 | | ~ 3s | Details | +| Terra | | | 0 | | ~ 6s | | +| Terra 2.0 | | | 0 | | ~ 6s | | +| Unichain | 200 | 201 | | finalized | ~ 18min | | +| World Chain | | | 0 | | ~ 18min | | +| X Layer | 200 | 201 | | finalized | ~ 16min | | +| XPLA | | | 0 | | ~ 5s | | + --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Architecture -description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. -categories: NTT, Transfer +title: Contract Addresses +description: This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. +categories: Reference --- -## Introduction +# Contract Addresses -The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. +## Core Contracts + + + -For the technical implementations of the functions, refer to the [Managers and Transceivers](/docs/build/transfers/native-token-transfers/managers-transceivers/){target=\_blank} page. +=== "Mainnet" -## System Components + | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | +| Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | +| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Algorand | 842125965 | +| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | +| Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | +| Avalanche | 0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c | +| Base | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Berachain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| Blast | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| BNB Smart Chain | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | +| Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | +| Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | +| NEAR | contract.wormhole_crypto.near | +| Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | +| Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | +| Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | +| Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | +| Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | +| Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | +| Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | +| X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | -The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. +=== "Testnet" -### Managers + | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | +| Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | +| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | +| Algorand | 86525623 | +| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | +| Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | +| Avalanche | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | +| Base Sepolia | 0x79A1027a6A159502049F10906D333EC57E95F083 | +| Berachain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Blast | 0x473e002D7add6fB67a4964F13bFd61280Ca46886 | +| BNB Smart Chain | 0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D | +| Celo | 0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56 | +| Fantom | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | +| Gnosis | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| HyperEVM | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | +| Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | +| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | +| Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | +| Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | +| Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | +| Monad | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Moonbeam | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | +| NEAR | wormhole.wormhole.testnet | +| Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | +| Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | +| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | +| Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | +| Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | +| Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | +| Pythnet | EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z | +| Scroll | 0x055F47F1250012C6B20c436570a76e52c17Af2D5 | +| Sei | sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s | +| Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | +| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | +| Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | +| Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | +| X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | +| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | -_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. +=== "Devnet" -Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. + | Ethereum | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | +| Solana | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | +| Algorand | 1004 | +| Aptos | 0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017 | +| BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | +| NEAR | wormhole.test.near | +| Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | +| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | +| Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | + -A manager is responsible for: +## Token Bridge -- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer -- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers - - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted - - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded + + - Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit +=== "Mainnet" -- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed -- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility + | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | +| Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | +| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | +| Algorand | 842126029 | +| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | +| Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | +| Avalanche | 0x0e082F06FF657D94310cB8cE8B0D9a04541d8052 | +| Base | 0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627 | +| Berachain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| Blast | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| BNB Smart Chain | 0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7 | +| Celo | 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed | +| Fantom | 0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2 | +| Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | +| Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | +| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | +| Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | +| NEAR | contract.portalbridge.near | +| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | +| Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | +| Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | +| Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | +| Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | +| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | +| Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | +| Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | +| X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | +| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | -### Transceivers +=== "Testnet" -_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. + | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | +| Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | +| Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | +| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | +| Algorand | 86525641 | +| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | +| Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Avalanche | 0x61E44E506Ca5659E6c0bba9b678586fA2d729756 | +| Base Sepolia | 0x86F55A04690fd7815A3D802bD587e83eA888B239 | +| Berachain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Blast | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | +| BNB Smart Chain | 0x9dcF9D205C9De35334D646BeE44b2D2859712A09 | +| Celo | 0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153 | +| Fantom | 0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8 | +| HyperEVM | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | +| Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | +| Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | +| Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | +| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | +| Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | +| Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | +| Monad | 0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659 | +| Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | +| NEAR | token.wormhole.testnet | +| Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | +| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | +| Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | +| Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | +| Sei | sei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2 | +| Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | +| SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | +| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | +| Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | +| Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | +| X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | +| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | -While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. +=== "Devnet" -Transceivers are entrusted with several responsibilities: + | Ethereum | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | +| Solana | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | +| Algorand | 1006 | +| Aptos | 0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31 | +| BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | +| NEAR | token.test.near | +| Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | +| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | +| Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | + -- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing -- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer -- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed +## Wormhole Relayer -How it works: + + -1. The transceiver receives instructions from the manager to send messages across chains -2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred -3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain +=== "Mainnet" -![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) + | Ethereum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Arbitrum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Avalanche | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Base | 0x706f82e9bb5b0813501714ab5974216704980e31 | +| Berachain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Blast | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| BNB Smart Chain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Celo | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Fantom | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Ink | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Kaia | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Mantle | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Moonbeam | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | +| X Layer | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -!!! note - [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. +=== "Testnet" -#### Custom Transceivers + | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. +=== "Devnet" -NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + -![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) +## CCTP -The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. + + -For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. +=== "Mainnet" -## Lifecycle of a Message + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. +=== "Testnet" -### Transfer + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. +=== "Devnet" -In both cases: + N/A + + -- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain -- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain +## Settlement Token Router -Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. +=== "Mainnet" -### Rate Limit + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. +=== "Testnet" -- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error -- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -Both chains emit events or logs when transfers are rate-limited or queued. +## Read-Only Deployments -### Send +=== "Mainnet" -After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message -- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. +--- END CONTENT --- -In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ +--- BEGIN CONTENT --- +--- +title: Supported Networks +description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +categories: Reference +--- -### Receive +# Supported Networks -Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. +Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. -- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers -- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing +## Supported Environments -In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. +- [EVM (Ethereum and compatible chains)](#evm) +- [SVM (Solana and compatible chains)](#svm) +- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) +- [AVM (Algorand)](#avm) +- [NEAR VM (NEAR)](#near-vm) +- [Move VM (Aptos)](#move-vm) +- [Sui Move VM (Sui)](#sui-move-vm) -### Mint or Unlock +## Supported Blockchains by Environment -Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. + + +
-- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred -- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced +### EVM -In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. ---- END CONTENT --- +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- +### SVM -# Deployment Models +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. +### AVM -## Hub-and-Spoke +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. +### CosmWasm -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain +### Move VM -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -## Burn-and-Mint +### NEAR VM -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -This model best suits new token deployments or projects willing to upgrade existing contracts. +### Sui Move VM -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- -title: A Quick Look at Native Token Transfers -description: This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer +title: Testnet Faucets +description: This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. +categories: Reference --- -# Native Token Transfers +# Testnet Faucets ## Get Started -This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. +Don't let the need for testnet tokens get in the way of buildling your next great idea with Wormhole. Use this guide to quickly locate the testnet token faucets you need to deploy and test applications and contracts on Wormhole's supported networks. -
+ + +
-- :octicons-question-16:{ .lg .middle } **Overview** +### EVM - --- +| Ethereum Holesky | EVM | ETH | Alchemy Faucet | +| Ethereum Sepolia | EVM | ETH | Alchemy Faucet | +| Acala | EVM | ACA | Discord Faucet | +| Arbitrum Sepolia | EVM | ETH | List of Faucets | +| Avalanche | EVM | AVAX | Official Avalanche Faucet | +| Base Sepolia | EVM | ETH | List of Faucets | +| Berachain | EVM | BERA | Official Berachain Faucet | +| Blast | EVM | ETH | List of Faucets | +| BNB Smart Chain | EVM | BNB | Official BNB Faucet | +| Celo | EVM | CELO | Official Celo Faucet | +| Fantom | EVM | FTM | Official Fantom Faucet | +| Gnosis | EVM | xDAI | Official Gnosis Faucet | +| HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | +| Ink | EVM | ETH | Official Ink Faucet | +| Kaia | EVM | KAIA | Official Kaia Faucet | +| Karura | EVM | ACA | Discord Faucet | +| Linea | EVM | ETH | List of Faucets | +| Mantle | EVM | MNT | Official Mantle Faucet | +| Monad | EVM | MON | Official Monad Faucet | +| Moonbeam | EVM | DEV | Official Moonbeam Faucet | +| Neon | EVM | NEON | Official Neon Faucet | +| Oasis | EVM | TEST | Official Oasis Faucet | +| Optimism Sepolia | EVM | ETH | Superchain Faucet | +| Polygon Amoy | EVM | POL | Official Polygon Faucet | +| Scroll | EVM | ETH | List of Faucets | +| Unichain | EVM | ETH | QuickNode Faucet | +| World Chain | EVM | ETH | Alchemy Faucet | +| X Layer | EVM | OKB | X Layer Official Faucet | + +### SVM - Dive into an introduction to NTT and discover what NTT is, what its key features are, and the available integration paths. +| Pythnet | SVM | ETH | Superchain Faucet | - [:custom-arrow: Learn more about NTT](/docs/learn/transfers/native-token-transfers/overview/) +### AVM -- :octicons-question-16:{ .lg .middle } **Architecture** +| Algorand | AVM | ALGO | Official Algorand Faucet | - --- +### CosmWasm + +| Celestia | CosmWasm | TIA | Discord Faucet | +| Cosmos Hub | CosmWasm | ATOM | Discord Faucet | +| Evmos | CosmWasm | TEVMOS | Official Evmos Faucet | +| Injective | CosmWasm | INJ | Official Injective Faucet | +| Kujira | CosmWasm | KUJI | Discord Faucet | +| Neutron | CosmWasm | NTRN | List of Faucets | +| Noble | CosmWasm | USDC | Circle Faucet | +| Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | +| SEDA | CosmWasm | SEDA | Official SEDA Faucet | +| Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | +| Terra | CosmWasm | LUNA | Terra Official Faucet | +| Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | +| XPLA | CosmWasm | XPLA | XPLA Official Faucet | - Explore NTT's architecture to understand its core components and how they work together to manage cross-chain communication. +### Move VM - [:custom-arrow: Discover how NTT works](/docs/products/native-token-transfers/concepts/architecture/) +| Aptos | Move VM | APT | Official Aptos Faucet | -- :octicons-book-16:{ .lg .middle } **Deployment Models** +### NEAR VM - --- +| NEAR | NEAR VM | NEAR | Official NEAR Faucet | - The NTT framework offers two deployment models for different token management needs: the hub-and-spoke and burn-and-mint models. +### Sui Move VM - [:custom-arrow: Check out the deployment models](/docs/learn/transfers/native-token-transfers/deployment/) +| Sui | Sui Move VM | SUI | List of Faucets | +
+ +--- END CONTENT --- -- :octicons-shield-lock-16:{ .lg .middle } **Security** +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- - --- +# Wormhole Formatted Addresses - Explore NTT's security measures, including the Global Accountant and governance strategies for seamless token safety. +## Introduction - [:custom-arrow: Review the security measures](/docs/learn/transfers/native-token-transfers/security/) +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. -
+This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. -## Next Steps +## Platform-Specific Address Formats -Ready to dive in and start building? Check out the following resources to begin the deployment process and make the most of your deployment. +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. -
+Here’s an overview of the native address formats and how they are normalized to the Wormhole format: -- :octicons-rocket-16:{ .lg .middle } **Deploy NTT** +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | - --- +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. - Explore detailed guides that walk you through the entire deployment process, from installing the NTT CLI to deploying NTT across supported chains. +### Address Format Handling - [:custom-arrow: Deploy now using the NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/) +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: -- :octicons-checklist-16:{ .lg .middle } **Post Deployment Recommendations** +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; +``` - --- +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. - Already deployed your NTT project? Check out these post deployment recommendations and integration demos to get the most out of your deployment. +## Universal Address Methods - [:custom-arrow: Get the most of out your NTT deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/) +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. -
---- END CONTENT --- +Key functions: -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format -# Native Token Transfers + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); + ``` -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` -## Introduction + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations -## Key Features + ```typescript + console.log(universalAddress.toString()); + ``` -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds +## Convert Between Native and Wormhole Formatted Addresses -## Integration Paths +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. +### Convert a Native Address to a Wormhole Formatted Address -### Native Token Transfers Framework +Example conversions for EVM and Solana: -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. +=== "EVM" -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} +=== "Solana" -### Token Bridge + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains +The result is a standardized address format that is ready for cross-chain operations. -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. +### Convert Back to Native Addresses -## Supported Token Standards +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); -Doc-Content: https://wormhole.com/docs/learn/transfers/native-token-transfers/security/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Security -description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -categories: NTT, Transfer ---- +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` -# Security +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. -## Global Accountant +## Use Cases for Wormhole Formatted Addresses -The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. +### Cross-chain Token Transfers -This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. -[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. +### Smart Contract Interactions -## Governance and Upgradeability +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. -Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. +### DApp Development -The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. -- Adding or removing a transceiver address from the registry -- Setting the token contract address on a bridging contract -- Setting the Wormhole Core Contract address on a bridging contract -- Setting the registered bridging contract address on the token contract +### Relayers and Infrastructure -This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ @@ -17347,478 +16218,608 @@ The protocol provides mechanisms for unlocking the fee once the bridging process - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/ +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ --- BEGIN CONTENT --- --- -title: Wormhole Settlement -description: Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. +title: Wormhole Settlement FAQs +description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. categories: Settlement, Transfer --- -# Wormhole Settlement - -## Get Started - -This section covers Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. - -
- -- :octicons-question-16:{ .lg .middle } **Overview** +# Wormhole Settlement FAQs - --- +## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? - Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. - [:custom-arrow: Learn more about Wormhole Settlement](/docs/learn/transfers/settlement/overview/) +## What happens if no solver participates in the auction? -- :octicons-question-16:{ .lg .middle } **Protocol Architectures** +If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. - --- +## What guarantees does Wormhole Settlement provide for message execution? - Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP — for scalable, efficient cross-chain asset transfers. +After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). - [:custom-arrow: Discover protocol architectures](/docs/products/settlement/concepts/architecture/) +If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ +--- BEGIN CONTENT --- +TODO --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/learn/transfers/settlement/overview/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +title: Wormhole Settlement Liquidity Layer +description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. categories: Settlement, Transfer --- -# Wormhole Settlement Overview +# Build on the Wormhole Liquidity Layer ## Introduction -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/learn/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. +The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. +## EVM Functions -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. +See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. -### How Does It Work? +### Fast Market Order -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +```solidity title="`placeFastMarketOrder` Interface" +function placeFastMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, + uint128 maxFee, + uint32 deadline +) external payable returns (uint64 sequence, uint64 fastSequence); +``` -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +??? interface "Parameters `placeFastMarketOrder()`" -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). + `amountIn` ++"uint128"++ -### Token Transfer Flow + The amount to transfer. -The transfer process is simple yet secure, involving a few key steps: + --- -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody + `targetChain` ++"uint16"++ -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) + Target chain ID. -### Key Features of the Token Bridge + --- -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. + `redeemer` ++"bytes32"++ -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. + Redeemer contract address. -### Message and Payload Structure + --- -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. + `redeemerMessage` ++"bytes"++ -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract + An arbitrary payload for the redeemer. -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. + --- -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. + `maxFee` ++"uint128"++ -### Security and Authorization + The maximum fee the user wants to pay to execute a fast transfer. -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. + --- -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. + `deadline` ++"uint32"++ -### Portal Bridge + The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- +The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. -Doc-Content: https://wormhole.com/docs/tutorials/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect Tutorials -description: Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -categories: Connect, Transfer ---- +### Market Order -# Connect +The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. -Wormhole Connect makes it simple to link your application to multiple blockchain ecosystems. These tutorials will teach you how to integrate Connect into your projects, streamline cross-chain interactions, simplify user onboarding, and deliver a smoother overall experience. +```solidity title="`placeMarketOrder` Interface" +function placeMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, +) external payable returns (uint64 sequence, uint64 protocolSequence); +``` -## Tutorials +??? interface "Parameters `placeMarketOrder()`" -
+ `amountIn` ++"uint128"++ -- :octicons-repo-16:{ .lg .middle } **Integrate Connect into a React DApp** + The amount to transfer. --- - Learn how to incorporate Wormhole Connect into a React application. This step-by-step tutorial guides you through enabling cross-chain token transfers and interactions, bridging assets between networks, and enhancing the user experience with streamlined blockchain connectivity. - - [:custom-arrow: Start building](/docs/products/connect/tutorials/react-dapp/) + `targetChain` ++"uint16"++ -
+ Target chain ID. -## Additional Resources + --- -
+ `redeemer` ++"bytes32"++ -- :octicons-tools-16:{ .lg .middle } **Connect** + Redeemer contract address. --- - Get deeper insights into setting up and customizing Wormhole Connect. Explore advanced guides, best practices, and configuration tips to streamline your cross-chain integrations. + `redeemerMessage` ++"bytes"++ - [:custom-arrow: Learn more](/docs/build/transfers/connect/) + An arbitrary payload for the redeemer. -
+The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ --- BEGIN CONTENT --- --- -title: Integrate Connect into a React DApp Tutorial -description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -categories: Connect, Transfer +title: Wormhole Settlement Solver +description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +categories: Settlement, Transfer --- -# Integrate Connect into a React DApp - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} +# Run a Wormhole Settlement Solver ## Introduction -In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. +This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. -While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. +A Solver is an off-chain agent responsible for: -## Prerequisites +- Listening to cross-chain transfer requests sent over Wormhole +- Bidding in auctions (on Solana) to fulfill each request +- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain +- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. -Before starting this tutorial, ensure you have the following: +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use -- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} -- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees +## Background -## Set Up Connect for Sui Transfers +The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: -### Create a React Project +1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details +2. `bid` - allows a solver to place or update a bid on the active auction +3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. +4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners -Start by setting up your React app: +These instructions work together to carry out the auction as follows: -1. Open your terminal and run the following command to create a new React app: +- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity +- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver +- The originating solver can repurpose the returned funds and use them to improve their bid +- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - ```bash - npx create-react-app connect-tutorial - ``` +When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. -2. Navigate into the project directory: +If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. - ```bash - cd connect-tutorial - ``` +## Testnet Example Solver -### Install Wormhole Connect +You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. -Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: +!!!warning + This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. -```bash -npm install @wormhole-foundation/wormhole-connect -``` +### Prerequisites -### Integrate Connect into the Application +In order to build and install dependencies locally in this repo, you will need: -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: +- node v20.18.1 +- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} -=== "JavaScript" +Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: - ```js - import logo from './logo.svg'; - import './App.css'; - import WormholeConnect from '@wormhole-foundation/wormhole-connect'; +```sh +make dependencies +``` - const config = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], - }; +### Set up Config - function App() { - return ; +The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. + +```json title="config.json" +{ + "environment": "Testnet", + "zmqChannels": { + "fastVaa": "tcp://localhost:6001", + "finalizedVaa": "tcp://localhost:6002" + }, + "publisher": { + "log": { + "level": "info" + }, + "vaaSpy": { + "host": "localhost:7073", + "enableObservationCleanup": true, + "observationSeenThresholdMs": 1500000, + "observationCleanupIntervalMs": 500, + "observationsToRemovePerInterval": 5, + "delayedThresholdMs": 60000 + } + }, + "solver": { + "log": { + "level": "info", + "filename": "logs/solver.log" + }, + "connection": { + "rpc": "", + "maxTransactionsPerSecond": 5, + "commitment": "processed", + "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", + "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", + "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "knownAtaOwners": [ + "Payer11111111111111111111111111111111111111", + "Payer11111111111111111111111111111111111112", + "Payer11111111111111111111111111111111111113" + ] + } + }, + "routerEndpoints": [ + { + "chain": "Sepolia", + "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Avalanche", + "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "OptimismSepolia", + "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "ArbitrumSepolia", + "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "BaseSepolia", + "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Polygon", + "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 } + ] +} +``` - export default App; - ``` +The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. -=== "TypeScript" +### Listen to Activity + +The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. + +```sh +NETWORK=testnet CONFIG=path/to/config.json make run-publisher +``` + +You should see output resembling: - ```ts - import './App.css'; - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - } from '@wormhole-foundation/wormhole-connect'; +
+ Start logging with info level. + 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet + 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 + 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 + 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 +
- function App() { - const config: WormholeConnectConfig = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], +To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: - ui: { - title: 'SUI Connect TS Demo', - }, - }; +=== "Linux" - const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - }; + ```sh + sudo sysctl -w net.core.rmem_max=2097152 + sudo sysctl -w net.core.rmem_default=2097152 + ``` - return ; - } +=== "MacOS" - export default App; + ```sh + sudo sysctl -w net.inet.udp.recvspace=2097152 ``` -- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment -- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche +### Running the Example Solver -### Customize Wormhole Connect +Using the same config for your publisher, run the example solver with the command below. -To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/build/transfers/connect/configuration/#introduction){target=\_blank}. +```sh +CONFIG=path/to/config.json make run-solver +``` -### Run the Application +It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. -Make sure you’re in the root directory of your React app, and run the following command to start the application: +This process reads the following environment variables: -```bash -npm start +```sh +SOLANA_PRIVATE_KEY_1= +SOLANA_PRIVATE_KEY_2= +SOLANA_PRIVATE_KEY_3= +SOLANA_PRIVATE_KEY_4= +SOLANA_PRIVATE_KEY_5= ``` -Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. +At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. -## Transfer Tokens from Sui to Fuji +The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. -Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. +Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. -To transfer tokens from Sui to Fuji in the Wormhole Connect interface: +An address lookup table is required to execute some transactions. Use the command below to create one. -1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer -2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network -3. Enter the amount of SUI tokens you wish to transfer +```sh +CONFIG=path/to/config.json make create-lut +``` - ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) +`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. -4. Choose to view other routes - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) +The example solver has the following toggles depending on which orders you want to fulfill: -5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) +- `enableCctpOrderPipeline()` +- `enableLocalOrderPipeline()` +- `enablePlaceInitialOffer()` +- `enableImproveOffer()` - !!! note - It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. +See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. - ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) +This example solver does NOT do the following: -6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain +- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called +- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it +- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want +--- END CONTENT --- - ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) +Doc-Content: https://wormhole.com/docs/products/settlement/overview/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet +Doc-Content: https://wormhole.com/docs/products/settlement/tutorials/.settlement-routes/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlements +description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. +--- - ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) +# Integrate Wormhole Settlement Routes Using the SDK -Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +## Introduction -## Claim Tokens on Fuji +This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. -After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. +## Prerequisites -![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) +Before beginning this project, make sure you have the following: -Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. +- **Wormhole SDK Route package** - installed using your preferred package manager -![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) + To install the package with npm, run the following command in your terminal: -## Resources + ```sh + npm install @mayan-finance/wormhole-sdk-route + ``` -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. + Alternatively, clone the repository and install dependencies: -## Conclusion + ```sh + git clone https://github.com/mayan-finance/wormhole-sdk-route.git + cd wormhole-sdk-route + npm install + ``` -In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. +- **Data for parameters** - you will need: + + - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains + - An contract address for the token you want to swap and the token you want to receive on the destination chain -By following these steps, you've learned how to: +## Configure and Setup -- Set up a React project tailored for cross-chain transfers -- Install and configure Wormhole Connect to support multiple blockchains -- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers -- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks +To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: -With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. ---- END CONTENT --- +- `sourceChain` - identifier for the chain where the swap begins +- `destinationChain` - identifier for the target chain +- `inputTokenAddress` - address of the token you want to swap +- `outputTokenAddress` - identifier/address of the desired token on the destination chain +- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) +- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) -Doc-Content: https://wormhole.com/docs/tutorials/ ---- BEGIN CONTENT --- ---- -title: Tutorials -description: Discover product-specific Wormhole tutorials. Learn setup, integration, and advanced features to develop cross-chain apps confidently. -template: root-index-page.html ---- +```ts +import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; -# Tutorials +const config: SwapRouteConfig = { + sourceChain: 'ethereum', + destinationChain: 'solana', + inputTokenAddress: '0xYourInputTokenAddress', + outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana + amount: '1000000000000000000', // For instance, 1 token in wei + slippageTolerance: 0.005, // 0.5% slippage tolerance + // Additional parameters may be included as needed +}; -In this section, you'll find tutorials focused on individual Wormhole products. Each product folder contains detailed guides to help you integrate and use specific Wormhole services, such as Token Bridge, Wormhole Connect, and more. Whether setting up your first product or diving deeper into advanced features, these tutorials will walk you through the entire process, from installation to implementation. +const swapRoute = new SwapRoute(config); +``` -## Browse Tutorials by Product +## Execute a Swap -## Get Started +Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. -
+### Fetch the Swap Route -- :octicons-arrow-switch-16:{ .lg .middle } **Connect** +Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: - --- +```ts +async function getSwapDetails() { + try { + const routeDetails = await swapRoute.getRoute(); + console.log('Optimal Swap Route:', routeDetails); + return routeDetails; + } catch (error) { + console.error('Error fetching swap route:', error); + throw error; + } +} - With Wormhole Connect, you can enable seamless connectivity between different blockchain ecosystems. These tutorials guide you through integrating Connect into your projects, allowing you to easily leverage cross-chain interactions, simplify onboarding, and improve user experience. +getSwapDetails(); +``` - [:custom-arrow: Start building](/docs/tutorials/connect/) +### Execute the Swap Transaction -- :octicons-sync-16:{ .lg .middle } **Multichain Assets** +Once the route is confirmed, execute the swap: - --- +```ts +async function executeSwap() { + try { + const txResponse = await swapRoute.executeSwap(); + console.log('Swap executed successfully:', txResponse); + // Further transaction handling (e.g., waiting for confirmation) can be added here. + } catch (error) { + console.error('Swap execution failed:', error); + } +} - Learn how to create, register, and manage wrapped multichain assets across multiple chains. These tutorials will guide you through the process of enabling asset transfers between supported networks. +executeSwap(); +``` - [:custom-arrow: Start building](/docs/tutorials/multichain-assets/) +## Complete Example Integration -- :octicons-people-16:{ .lg .middle } **MultiGov** +Below is a complete example that puts together configuration, route fetching, and swap execution: - --- +```ts +import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - Unleash the power of cross-chain governance with Multigov. These tutorials guide you through setting up and managing governance structures spanning multiple blockchains, enabling collective decision-making and coordinated upgrades across decentralized ecosystems. +async function performSwap() { + // Configure the swap parameters + const config: SwapRouteConfig = { + sourceChain: 'ethereum', + destinationChain: 'solana', + inputTokenAddress: '0xYourInputTokenAddress', + outputTokenAddress: 'So11111111111111111111111111111111111111112', + amount: '1000000000000000000', + slippageTolerance: 0.005, + // Include additional settings as needed + }; - [:custom-arrow: Start building](/docs/tutorials/multigov/) + // Initialize the swap route + const swapRoute = new SwapRoute(config); -- :octicons-file-code-16:{ .lg .middle } **Solidity SDK** + try { + // Retrieve the optimal swap route details + const routeDetails = await swapRoute.getRoute(); + console.log('Optimal Swap Route:', routeDetails); - --- + // Execute the swap transaction + const txResponse = await swapRoute.executeSwap(); + console.log('Swap Transaction Response:', txResponse); + } catch (error) { + console.error('An error occurred during the swap process:', error); + } +} - Learn to build smart contracts that communicate across multiple blockchains. These tutorials show you how to create robust cross-chain contracts, allowing your dApps to move beyond a single network and tap into global liquidity, functionality, and user bases. +performSwap(); +``` - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/) +## Error Handling and Troubleshooting -- :octicons-code-square-16:{ .lg .middle } **TypeScript SDK** +- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable +- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting +- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: - --- + ```ts + class MayanRefRoute extends MayanRoute { + override referrerAddress(): ReferrerAddresses | undefined { + return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; + } + } + ``` +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ +--- BEGIN CONTENT --- +--- +title: Token Bridge FAQs +description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +categories: Token-Bridge, Transfer +--- - Master the tools to build cross-chain applications with the Wormhole SDK. These tutorials cover installation to advanced functionality, helping you streamline development, reduce complexity, and quickly bring your ideas to life. +## FAQs - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/) +### Can ownership of wrapped tokens be transferred from the Token Bridge? -- :octicons-code-square-16:{ .lg .middle } **Wormholescan API** +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - --- + - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself + - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge - Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. +The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. - [:custom-arrow: Start building](/docs/tutorials/wormholescan/) +Relevant contracts: -
---- END CONTENT --- + - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} + - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} + - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} -Doc-Content: https://wormhole.com/docs/tutorials/multichain-assets/ ---- BEGIN CONTENT --- ---- -title: Multichain Assets Tutorials -description: Explore comprehensive, step-by-step tutorials on how to register, manage, and work with multichain assets within the Wormhole ecosystem. ---- +### How do I update the metadata of a wrapped token? -# Multichain Assets +Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -Multichain assets, often represented as wrapped tokens, enable seamless cross-chain interoperability. This section provides step-by-step tutorials for registering, managing, and working with these assets across different blockchains. +### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? -## Tutorials +You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. -
+### How can I update my wrapped token image on Solscan? -- :octicons-repo-16:{ .lg .middle } **Create Multichain Tokens** +Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. - --- +To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. +--- END CONTENT --- - Learn how to register your token on both a source and target chain, and create a wrapped version for seamless interoperability. +Doc-Content: https://wormhole.com/docs/products/token-bridge/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - [:custom-arrow: Register your assets now](/docs/products/token-bridge/tutorials/multichain-token/) +Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/transfer-wrapped-assets/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -
+Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +--- BEGIN CONTENT --- +TODO --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ @@ -17874,5591 +16875,5158 @@ Attestation is a key step in the process. It verifies your token’s metadata, e ![Send Attestation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp) -!!! note - - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token - - Ensure you have sufficient funds to cover transaction fees on the target chain +!!! note + - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token + - Ensure you have sufficient funds to cover transaction fees on the target chain + +## Create the Wrapped Token + +The final step is to create the wrapped token on the target chain. This token represents the original asset and enables its use within the target blockchain. + +1. Click **Create** to generate the wrapped token +2. Approve the transaction in your wallet when prompted + +![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) + +Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: + +![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) + +## Additional Steps and Recommendations + +After creating your multichain token, there are a few optional but highly recommended steps to ensure the best experience for users interacting with your token. + +### Add Your Token to the Wormhole Metadata List (Legacy) + +For legacy compatibility in the [**Advanced Tools**](https://portalbridge.com/advanced-tools/){target=\_blank} section of Portal Bridge, you can request updates to your token metadata. Follow these steps: + +1. Join the [Wormhole Discord server](https://discord.com/invite/wormholecrypto){target=\_blank} +2. Submit a request for metadata updates in the appropriate support channel + +!!! note + These updates only apply to the **Advanced Tools** section of Portal Bridge and will not update how your token appears in other Wormhole-powered apps or on blockchain explorers like Etherscan. + +### Update Metadata on Blockchain Explorers + +It is recommended that you update your token’s metadata on blockchain explorers such as Etherscan. This includes adding details like the token logo, price, and contract verification. + +1. Create an account on the relevant scanner and go to the [token update section](https://etherscan.io/tokenupdate){target=\_blank} (or the relevant scanner that you would like to update metadata on) +2. Copy and paste the wrapped contract address in the **Token Update Application Form** +3. Before proceeding to the next step, you will need to verify as the contract address owner on [Etherscan’s address verification tool](https://etherscan.io/verifyAddress/){target=\_blank} +4. Follow the directions to verify contract address ownership via MetaMask by reviewing the [guide on verifying address ownership](https://info.etherscan.com/how-to-verify-address-ownership/){target=\_blank} + - Given that Wormhole may be the contract owner, use the manual verification process by reaching out through the [Etherscan contact form](https://etherscan.io/contactus){target=\_blank}. The team will provide support as needed +5. Once the step above is completed, follow the [instructions to update token information](https://info.etherscan.com/how-to-update-token-information-on-token-page/){target=\_blank} +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/transfer-workflow/ +--- BEGIN CONTENT --- +--- +title: Transfer Tokens via Token Bridge Tutorial +description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +--- + +# Complete Token Transfer Workflow + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} + +## Introduction + +This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. + +By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: + + - EVM to EVM (e.g., Ethereum to Avalanche) + - EVM to non-EVM chains (e.g., Ethereum to Solana) + - Non-EVM to EVM chains (e.g., Sui to Avalanche) + - Non-EVM to non-EVM chains (e.g., Solana to Sui) + +Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. + +At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. + +## Prerequisites + +Before you begin, ensure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - Native tokens (testnet or mainnet) in Solana and Sui wallets + - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees + +## Supported Chains + +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. + +## Project Setup + +In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. + +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project + + ```bash + mkdir native-transfers + cd native-transfers + npm init -y + ``` + +2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries + + ```bash + npm install @wormhole-foundation/sdk dotenv tsx + ``` + +3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project + + ```bash + touch .env + ``` + + Inside the `.env` file, add your private keys. + + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" + ``` + + !!! note + Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. + +4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays + + 1. Create the helpers file + + ```bash + mkdir -p src/helpers + touch src/helpers/helpers.ts + ``` + + 2. Open the `helpers.ts` file and add the following code + + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + TokenId, + isTokenId, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import { config } from 'dotenv'; +config(); + +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} + +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} + +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext, + gasLimit?: bigint +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + const evmSignerOptions = gasLimit ? { gasLimit } : {}; + signer = await ( + await evm() + ).getSigner( + await chain.getRpc(), + getEnv('ETH_PRIVATE_KEY'), + evmSignerOptions + ); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); + break; + case 'Aptos': + signer = await ( + await aptos() + ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + +export async function getTokenDecimals< + N extends 'Mainnet' | 'Testnet' | 'Devnet' +>( + wh: Wormhole, + token: TokenId, + sendChain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : sendChain.config.nativeTokenDecimals; +} + + ``` + + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file + - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers + +## Check and Create Wrapped Tokens + +Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. -## Create the Wrapped Token +In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. -The final step is to create the wrapped token on the target chain. This token represents the original asset and enables its use within the target blockchain. +### Configure the Wrapped Token Script -1. Click **Create** to generate the wrapped token -2. Approve the transaction in your wallet when prompted +1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory -![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) + ```bash + mkdir -p src/scripts + touch src/scripts/create-wrapped.ts + ``` -Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: +2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions -![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; + ``` -## Additional Steps and Recommendations +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support -After creating your multichain token, there are a few optional but highly recommended steps to ensure the best experience for users interacting with your token. + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` -### Add Your Token to the Wormhole Metadata List (Legacy) + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. -For legacy compatibility in the [**Advanced Tools**](https://portalbridge.com/advanced-tools/){target=\_blank} section of Portal Bridge, you can request updates to your token metadata. Follow these steps: +4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) -1. Join the [Wormhole Discord server](https://discord.com/invite/wormholecrypto){target=\_blank} -2. Submit a request for metadata updates in the appropriate support channel + ```typescript + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); + ``` -!!! note - These updates only apply to the **Advanced Tools** section of Portal Bridge and will not update how your token appears in other Wormhole-powered apps or on blockchain explorers like Etherscan. +5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation -### Update Metadata on Blockchain Explorers + ```typescript + + ``` -It is recommended that you update your token’s metadata on blockchain explorers such as Etherscan. This includes adding details like the token logo, price, and contract verification. +6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation -1. Create an account on the relevant scanner and go to the [token update section](https://etherscan.io/tokenupdate){target=\_blank} (or the relevant scanner that you would like to update metadata on) -2. Copy and paste the wrapped contract address in the **Token Update Application Form** -3. Before proceeding to the next step, you will need to verify as the contract address owner on [Etherscan’s address verification tool](https://etherscan.io/verifyAddress/){target=\_blank} -4. Follow the directions to verify contract address ownership via MetaMask by reviewing the [guide on verifying address ownership](https://info.etherscan.com/how-to-verify-address-ownership/){target=\_blank} - - Given that Wormhole may be the contract owner, use the manual verification process by reaching out through the [Etherscan contact form](https://etherscan.io/contactus){target=\_blank}. The team will provide support as needed -5. Once the step above is completed, follow the [instructions to update token information](https://info.etherscan.com/how-to-update-token-information-on-token-page/){target=\_blank} ---- END CONTENT --- + ```typescript + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } + ``` -Doc-Content: https://wormhole.com/docs/tutorials/multigov/ ---- BEGIN CONTENT --- ---- -title: Step-by-Step MultiGov Tutorials -description: Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. -categories: MultiGov ---- + If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. -# MultiGov +7. **Set up the source chain signer** - the signer creates and submits the attestation transaction -Welcome to the MultiGov tutorials section. In this section, you will find tutorials that walk you through the key steps of working with MultiGov, providing clear instructions to help you get started. As you explore, you'll gain a deeper understanding of MultiGov's features and functionality. + ```typescript + + ``` -## Tutorials +8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step -
+ ```typescript + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); -- :octicons-repo-16:{ .lg .middle } **Cross-Chain Treasury Management Proposal** + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); + ``` - --- +9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure - Learn how to propose governance actions on a hub chain, gather votes from spoke chains, aggregate the results, and carry out the final decision. Following these steps, you’ll master end-to-end governance workflows spanning multiple networks. + ```typescript + console.log('Parsed Messages:', msgs); - [:custom-arrow: Start building](/docs/products/multigov/tutorials/treasury-proposal/) + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } + ``` -
+10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation -## Additional Resources + ```typescript + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); -
+ const tsx = await signSendWait(destChain, subAttestation, destSigner); + ``` -- :octicons-book-16:{ .lg .middle } **Governance Fundamentals** +11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain - --- + ```typescript + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } - Dive into Wormhole’s governance mechanisms. Understand how cross-chain governance works, proposal creation, voting, and execution. + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` - [:custom-arrow: Explore governance](/docs/learn/governance/) + If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. -- :octicons-tools-16:{ .lg .middle } **Implement MultiGov** +??? code "Complete script" + ```typescript + import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; - --- +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); - Integrate MultiGov into your smart contracts. Access reference code, best practices, and guidance for deploying cross-chain governance systems. + // Define the source and destination chains + const srcChain = wh.getChain('ArbitrumSepolia'); + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); + // Destination chain signer setup + const { signer: destSigner } = await getSigner(destChain, gasLimit); + const tbDest = await destChain.getTokenBridge(); - [:custom-arrow: Build with MultiGov](/docs/build/multigov/) + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } -
---- END CONTENT --- + // Source chain signer setup + const { signer: origSigner } = await getSigner(srcChain); -Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ ---- BEGIN CONTENT --- ---- -title: MultiGov Guides -description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. -categories: MultiGov ---- + // Create an attestation transaction on the source chain + const tbOrig = await srcChain.getTokenBridge(); + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); -# Cross-Chain treasury management proposal + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); -This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. + // Retrieve the Wormhole message ID from the attestation transaction + const msgs = await srcChain.parseTransaction(txid); + console.log('Parsed Messages:', msgs); -## Create a Proposal + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } -The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. + console.log('Token Address: ', vaa.payload.token.address); -In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. + // Submit the attestation on the destination chain + console.log('Attesting asset on destination chain...'); -Key actions: + const subAttestation = tbDest.submitAttestation( + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); -- Define the proposal targets (two transactions to the Message Dispatcher) -- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) -- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum -- Finally, we submit the proposal to the `HubGovernor` contract + const tsx = await signSendWait(destChain, subAttestation, destSigner); + console.log('Transaction hash: ', tsx); -```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Prepare proposal details -address[] memory targets = new address[](2); -targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; -targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; -uint256[] memory values = new uint256[](2); -values[0] = 0; -values[1] = 0; -bytes[] memory calldatas = new bytes[](2); -// Prepare message for Optimism to mint 10 W tokens -// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) -calldatas[0] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - OPTIMISM_WORMHOLE_CHAIN_ID, - [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], - [uint256(10 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -// Prepare message for Arbitrum to receive 15 ETH -calldatas[1] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - ARBITRUM_WORMHOLE_CHAIN_ID, - [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], - [uint256(15 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; -// Create the proposal -uint256 proposalId = governor.propose( - targets, values, calldatas, description -) -``` + // Poll for the wrapped asset until it's available + async function waitForIt() { + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } -??? interface "Parameters" + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` - `GOVERNOR_ADDRESS` ++"address"++ +### Run the Wrapped Token Creation - The address of the `HubGovernor` contract on Ethereum Mainnet. +Once the script is ready, execute it with: - --- +```bash +npx tsx src/scripts/create-wrapped.ts +``` - `targets` ++"address[]"++ +If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. - An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. +## Token Transfers - --- +In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. - `values` ++"uint256[]"++ +### Configure Transfer Details - An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. - --- +1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains - `calldatas` ++"bytes[]"++ + ```bash + touch src/scripts/native-transfer.ts + ``` - The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. +2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files - --- + ```typescript + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; + ``` - `description` ++"string"++ +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support - A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` -??? interface "Returns" +4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them - `proposalId` ++"uint256"++ + ```typescript + const rcvChain = wh.getChain('Solana'); + ``` - The ID of the newly created proposal on the hub chain. +5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains -## Vote on the Proposal via Spoke + ```typescript + const destination = await getSigner(rcvChain); + ``` -Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. +6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object -Key actions: + ```typescript + + ``` -- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain -- Cast a vote in support of the proposal +7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit -```solidity -// Connect to the SpokeVoteAggregator contract of the desired chain -SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); -// Cast a vote -uint8 support = 1; // 1 for supporting, 0 for opposing -uint256 weight = voteAggregator.castVote(proposalId, support); -``` + ```typescript + + ``` -??? interface "Parameters" +8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself - `VOTE_AGGREGATOR_ADDRESS` ++"address"++ + ```typescript + + ``` - The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). + !!! note + Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. + +9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function - --- + ```typescript + + ``` - `proposalId` ++"uint256"++ +10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` - The ID of the proposal created on the hub chain, which is being voted on. + ```typescript + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); + ``` - --- + Finally, we use `process.exit(0);` to close the script once the transfer completes - `support` ++"uint8"++ + ```typescript + })(); + ``` - The vote being cast (`1` for supporting the proposal, `0` for opposing). +### Token Transfer Logic -??? interface "Returns" +This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. - `weight` ++"uint256"++ +#### Defining the Token Transfer Function - The weight of the vote, determined by the voter’s token holdings on the spoke chain. +The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. -## Vote Aggregation +```typescript +wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic +import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; -In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); -Key actions: + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); -- Aggregate votes from different chains and submit them to the hub chain for tallying + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -```solidity -// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) -hubVotePool.crossChainVote(queryResponseRaw, signatures); -``` + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); -??? interface "Parameters" + // Define the amount of tokens to transfer + const amt = '1'; - `queryResponseRaw` ++"bytes"++ + // Set automatic transfer to false for manual transfer + const automatic = false; - The raw vote data from the spoke chains. + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); - --- + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); - `signatures` ++"bytes"++ + process.exit(0); +})(); - Cryptographic signatures that verify the validity of the votes from the spoke chains. +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); -## Execute Proposal and Dispatch Cross-Chain Messages + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); -After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; -Key actions: + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); -- Execute the proposal after the voting period ends and the proposal passes -- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); -```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Standard timelock execution -governor.execute(targets, values, calldatas, descriptionHash); + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +} + ``` -??? interface "Parameters" - - `governor` ++"HubGovernor"++ +#### Steps to Transfer Tokens - The `HubGovernor` contract instance. +The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: - --- +1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step - `targets` ++"address[]"++ + ```typescript + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); + ``` - An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). +2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying - --- + ```typescript + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); - `values` ++"uint256[]"++ + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; + ``` - An array of values (in Wei) associated with each transaction (both are zero in this case). +3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process - --- + ```typescript + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + ``` - `calldatas` ++"bytes[]"++ + - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} - The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). + ???- note "How Cross-Chain Transfers Work in the Background" + When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: - --- + - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount + - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains + - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network + - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer - `descriptionHash` ++"bytes32"++ + This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. - A hash of the proposal’s description, used to verify the proposal before execution. +4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain -??? interface "Returns" + ```typescript + + ``` - No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. +5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer -Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. ---- END CONTENT --- + ```typescript + console.log(`Completed Transfer: `, destTxids); + ``` -Doc-Content: https://wormhole.com/docs/tutorials/settlement/.index/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement -description: Follow step-by-step tutorials to integrate Wormhole Settlement Routes using the SDK for seamless cross-chain swaps and efficient asset transfers. ---- +??? code "Complete script" + ```typescript + import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; -# Wormhole Settlement +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); -This section provides hands-on tutorials to help you integrate Wormhole Settlement Routes into your application. Learn how to use the SDK to manage cross-chain swaps, optimize fees, and streamline transaction execution. + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); -## Tutorials + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -
+ // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); -- :octicons-repo-16:{ .lg .middle } **Integrate Wormhole Settlement Routes using the SDK** + // Define the amount of tokens to transfer + const amt = '1'; - --- + // Set automatic transfer to false for manual transfer + const automatic = false; - Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); - [:custom-arrow: Integrate Settlement Routes](/docs/tutorials/settlement/settlement-routes/) + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); -
---- END CONTENT --- + process.exit(0); +})(); -Doc-Content: https://wormhole.com/docs/tutorials/settlement/.settlement-routes/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlements -description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. ---- +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); -# Integrate Wormhole Settlement Routes Using the SDK + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); -## Introduction + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; -This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); -## Prerequisites + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); -Before beginning this project, make sure you have the following: + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +} + + ``` -- **Wormhole SDK Route package** - installed using your preferred package manager +### Run the Native Token Transfer - To install the package with npm, run the following command in your terminal: +Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: - ```sh - npm install @mayan-finance/wormhole-sdk-route - ``` +```bash +npx tsx src/scripts/native-transfer.ts +``` - Alternatively, clone the repository and install dependencies: +This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). - ```sh - git clone https://github.com/mayan-finance/wormhole-sdk-route.git - cd wormhole-sdk-route - npm install - ``` +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. -- **Data for parameters** - you will need: - - - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - - An contract address for the token you want to swap and the token you want to receive on the destination chain +## Resources -## Configure and Setup +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. -To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: +## Conclusion -- `sourceChain` - identifier for the chain where the swap begins -- `destinationChain` - identifier for the target chain -- `inputTokenAddress` - address of the token you want to swap -- `outputTokenAddress` - identifier/address of the desired token on the destination chain -- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) -- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) +You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; +The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. +--- END CONTENT --- -const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana - amount: '1000000000000000000', // For instance, 1 token in wei - slippageTolerance: 0.005, // 0.5% slippage tolerance - // Additional parameters may be included as needed -}; +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -const swapRoute = new SwapRoute(config); -``` +# Architecture -## Execute a Swap +## Overview -Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. -### Fetch the Swap Route +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) -Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: -```ts -async function getSwapDetails() { - try { - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - return routeDetails; - } catch (error) { - console.error('Error fetching swap route:', error); - throw error; - } -} +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. -getSwapDetails(); -``` + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: -### Execute the Swap Transaction + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract -Once the route is confirmed, execute the swap: +## On-Chain Components -```ts -async function executeSwap() { - try { - const txResponse = await swapRoute.executeSwap(); - console.log('Swap executed successfully:', txResponse); - // Further transaction handling (e.g., waiting for confirmation) can be added here. - } catch (error) { - console.error('Swap execution failed:', error); - } -} +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract -executeSwap(); -``` +## Off-Chain Components -## Complete Example Integration +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers -Below is a complete example that puts together configuration, route fetching, and swap execution: +## Next Steps -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; +
-async function performSwap() { - // Configure the swap parameters - const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', - amount: '1000000000000000000', - slippageTolerance: 0.005, - // Include additional settings as needed - }; +- :octicons-book-16:{ .lg .middle } **Core Contracts** - // Initialize the swap route - const swapRoute = new SwapRoute(config); + --- - try { - // Retrieve the optimal swap route details - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - // Execute the swap transaction - const txResponse = await swapRoute.executeSwap(); - console.log('Swap Transaction Response:', txResponse); - } catch (error) { - console.error('An error occurred during the swap process:', error); - } -} + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) -performSwap(); -``` +- :octicons-tools-16:{ .lg .middle } **Core Messaging** -## Error Handling and Troubleshooting + --- -- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable -- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting -- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. - ```ts - class MayanRefRoute extends MayanRoute { - override referrerAddress(): ReferrerAddresses | undefined { - return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; - } - } - ``` + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) + +
--- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ --- BEGIN CONTENT --- --- -title: Create Cross-Chain Contracts -description: Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. +title: Run a Relayer +description: Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +categories: Relayers --- -# Create Cross-Chain Messaging Contracts - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} +# Run a Custom Relayer ## Introduction -Wormhole's cross-chain messaging allows smart contracts to interact seamlessly across multiple blockchains. This enables developers to build decentralized applications that leverage the strengths of different networks, whether it's Avalanche, Celo, Ethereum, or beyond. In this tutorial, we'll explore using [Wormhole's Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} to create cross-chain contracts to send and receive messages across chains. +Relayers play a crucial role in cross-chain communication, ensuring that messages are transferred seamlessly between different blockchains. While Wormhole relayers provide a reliable way to handle these transfers, they might not always meet every application's unique requirements. -Wormhole's messaging infrastructure simplifies data transmission, event triggering, and transaction initiation across blockchains. In this tutorial, we'll guide you through a simple yet powerful hands-on demonstration that showcases this practical capability. We'll deploy contracts on two Testnets—Avalanche Fuji and Celo Alfajores—and send messages from one chain to another. This tutorial is perfect for those new to cross-chain development and seeking hands-on experience with Wormhole's powerful toolkit. +Custom relayers address these limitations by offering tailored solutions that cater to the distinct needs of your application. Developing a custom relayer gives you complete control over message processing, delivery mechanisms, and integration with existing systems. This customization allows for optimized performance and the ability to implement specific features that Wormhole-deployed relayers might not support. -By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. +A custom relayer might be as simple as an in-browser process that polls the API for the availability of a VAA after submitting a transaction and delivers it to the target chain. It might also be implemented with a Spy coupled with some daemon listening for VAAs from a relevant chain ID and emitter, then taking action when one is observed. -This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. +This guide teaches you how to set up and configure a custom relayer for efficient message handling. You'll start by understanding how to uniquely identify a VAA using its emitter address, sequence ID, and chain ID. Then, you'll explore the Relayer Engine, a package that provides a framework for building custom relayers, and learn how to fetch and handle VAAs using the Wormhole SDK. -## Wormhole Overview +## Get Started with a Custom Relayer -We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. +To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs. -Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. +
+ ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp) +
The off-chain components outlined in blue must be implemented.
+
-![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +### How to Uniquely Identify a VAA -## Prerequisites +Regardless of the environment, to get the VAA you intend to relay, you need: -Before starting this tutorial, ensure you have the following: +- The `emitter` address +- The `sequence` ID of the message you're interested in +- The `chainId` for the chain that emitted the message -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts -- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees -- Wallet private key +With these three components, you're able to uniquely identify a VAA and process it. -## Build Cross-Chain Messaging Contracts +## Use the Relayer Engine -In this section, we'll deploy two smart contracts: one to send a message from Avalanche Fuji and another to receive it on Celo Alfajores. The contracts interact with the Wormhole relayer to transmit messages across chains. +The [`relayer-engine`](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} is a package that provides the structure and a starting point for a custom relayer. -At a high level, our contracts will: +With the Relayer Engine, a developer can write specific logic for filtering to receive only the messages they care about. -1. Send a message from Avalanche to Celo using the Wormhole relayer -2. Receive and process the message on Celo, logging the content of the message +Once a Wormhole message is received, the developer may apply additional logic to parse custom payloads or submit the Verifiable Action Approvals (VAA) to one or many destination chains. -Before diving into the deployment steps, let's first break down key parts of the contracts. +To use the Relayer Engine, a developer may specify how to relay Wormhole messages for their app using an idiomatic Express/Koa middleware-inspired API, then let the library handle all the details. -### Sender Contract: MessageSender +### Install the Relayer Engine -The `MessageSender` contract is responsible for quoting the cost of sending a message cross-chain and then sending that message. +First, install the `relayer-engine` package with your favorite package manager: -Key functions include: +```bash +npm i @wormhole-foundation/relayer-engine +``` - - **`quoteCrossChainCost`** - calculates the cost of delivering a message to the target chain using the Wormhole relayer - - **`sendMessage`** - encodes the message and sends it to the target chain and contract address using the Wormhole relayer +### Get Started with the Relayer Engine -Here's the core of the contract: +In the following example, you'll: -```solidity -uint16 targetChain, - address targetAddress, - string memory message - ) external payable { - uint256 cost = quoteCrossChainCost(targetChain); +1. Set up a `StandardRelayerApp`, passing configuration options for our relayer +2. Add a filter to capture only those messages our app cares about, with a callback to do _something_ with the VAA once received +3. Start the relayer app - require( - msg.value >= cost, - "Insufficient funds for cross-chain delivery" - ); +```typescript +import { + Environment, + StandardRelayerApp, + StandardRelayerContext, +} from '@wormhole-foundation/relayer-engine'; +import { CHAIN_ID_SOLANA } from '@certusone/wormhole-sdk'; - wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(message, msg.sender), - 0, - GAS_LIMIT - ); +(async function main() { + // Initialize relayer engine app and pass relevant config options + const app = new StandardRelayerApp( + Environment.TESTNET, + // Other app specific config options can be set here for things + // like retries, logger, or redis connection settings + { + name: 'ExampleRelayer', + } + ); + + // Add a filter with a callback that will be invoked + // on finding a VAA that matches the filter + app.chain(CHAIN_ID_SOLANA).address( + // Emitter address on Solana + 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', + // Callback function to invoke on new message + async (ctx, next) => { + const vaa = ctx.vaa; + const hash = ctx.sourceTxHash; + console.log( + `Got a VAA with sequence: ${vaa.sequence} from with txhash: ${hash}` + ); } + ); + + // Add and configure any other middleware here + + // Start app. Blocks until unrecoverable error or process is stopped + await app.listen(); +})(); + ``` -You can find the full code for the `MessageSender.sol` below. +The first meaningful line instantiates the `StandardRelayerApp`, a subclass of the `RelayerApp` with standard defaults. -??? code "MessageSender.sol" +```typescript +export class StandardRelayerApp< + ContextT extends StandardRelayerContext = StandardRelayerContext, +> extends RelayerApp { + // ... + constructor(env: Environment, opts: StandardRelayerAppOpts) { +``` - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +The only field you pass in the `StandardRelayerAppOpts` is the name to help identify log messages and reserve a namespace in Redis. -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; +??? code "`StandardRelayerAppOpts`" -contract MessageSender { - IWormholeRelayer public wormholeRelayer; - uint256 constant GAS_LIMIT = 50000; + Other options can be passed to the `StandardRelayerApp` constructor to configure the app further. - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } + ```typescript + wormholeRpcs?: string[]; // List of URLs from which to query missed VAAs +concurrency?: number; // How many concurrent requests to make for workflows +spyEndpoint?: string; // The hostname and port of our Spy +logger?: Logger; // A custom Logger +privateKeys?: Partial<{ [k in ChainId]: any[]; }>; // A set of keys that can be used to sign and send transactions +tokensByChain?: TokensByChain; // The token list we care about +workflows?: { retries: number; }; // How many times to retry a given workflow +providers?: ProvidersOpts; // Configuration for the default providers +fetchSourceTxhash?: boolean; // whether or not to get the original transaction ID/hash +// Redis config +redisClusterEndpoints?: ClusterNode[]; +redisCluster?: ClusterOptions; +redis?: RedisOptions; + ``` - function quoteCrossChainCost( - uint16 targetChain - ) public view returns (uint256 cost) { - (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); - } +The next meaningful line in the example adds a filter middleware component. This middleware will cause the relayer app to request a subscription from the Spy for any VAAs that match the criteria and invoke the callback with the VAA. - function sendMessage( - uint16 targetChain, - address targetAddress, - string memory message - ) external payable { - uint256 cost = quoteCrossChainCost(targetChain); +If you'd like your program to subscribe to `multiple` chains and addresses, you can call the same method several times or use the `multiple` helper. - require( - msg.value >= cost, - "Insufficient funds for cross-chain delivery" - ); +```typescript +app.multiple( + { + [CHAIN_ID_SOLANA]: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', + [CHAIN_ID_ETH]: ['0xabc1230000000...', '0xdef456000...'], + }, + myCallback +); +``` - wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(message, msg.sender), - 0, - GAS_LIMIT - ); - } -} - ``` +The last line in the simple example runs `await app.listen()`, which starts the relayer engine. Once started, the Relayer Engine issues subscription requests to the Spy and begins any other workflows (e.g., tracking missed VAAs). -### Receiver Contract: MessageReceiver +This will run until the process is killed or encounters an unrecoverable error. To gracefully shut down the relayer, call `app.stop()`. -The `MessageReceiver` contract handles incoming cross-chain messages. When a message arrives, it decodes the payload and logs the message content. It ensures that only authorized contracts can send and process messages, adding an extra layer of security in cross-chain communication. +The source code for this example is available in the [`relayer-engine` repository](https://github.com/wormhole-foundation/relayer-engine/blob/main/examples/simple/src/app.ts){target=\_blank}. -#### Emitter Validation and Registration +## Start Background Processes -In cross-chain messaging, validating the sender is essential to prevent unauthorized contracts from sending messages. The `isRegisteredSender` modifier ensures that messages can only be processed if they come from the registered contract on the source chain. This guards against malicious messages and enhances security. +!!! note + These processes _must_ be running for the relayer app below to work. -Key implementation details include: +Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. - - **`registeredSender`** - stores the address of the registered sender contract - - **`setRegisteredSender`** - registers the sender's contract address on the source chain. It ensures that only registered contracts can send messages, preventing unauthorized senders - - **`isRegisteredSender`** - restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication +More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. -```solidity +### Wormhole Network Spy -require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } +For our relayer app to receive messages, a local Spy must be running that watches the Guardian network. Our relayer app will receive updates from this Spy. - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -``` +=== "Mainnet Spy" -#### Message Processing + ```bash + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env mainnet + ``` -The `receiveWormholeMessages` is the core function that processes the received message. It checks that the Wormhole relayer sent the message, decodes the payload, and emits an event with the message content. It is essential to verify the message sender to prevent unauthorized messages. +=== "Testnet Spy" -```solidity -bytes memory payload, - bytes[] memory, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 - ) public payable override isRegisteredSender(sourceChain, sourceAddress) { - require( - msg.sender == address(wormholeRelayer), - "Only the Wormhole relayer can call this function" - ); + ```bash + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env testnet + ``` - // Decode the payload to extract the message - string memory message = abi.decode(payload, (string)); +### Redis Persistence - // Example use of sourceChain for logging - if (sourceChain != 0) { - emit SourceChainLogged(sourceChain); - } +!!! note + While you're using [Redis](https://redis.io/docs/latest/develop/get-started/){target=\_blank} here, the persistence layer can be swapped out for some other database by implementing the appropriate [interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank}. - // Emit an event with the received message - emit MessageReceived(message); - } -``` +A Redis instance must also be available to persist job data for fetching VAAs from the Spy. -You can find the full code for the `MessageReceiver.sol` below. +```bash +docker run --rm -p 6379:6379 --name redis-docker -d redis +``` -??? code "MessageReceiver.sol" +## Use the Wormhole SDK - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +!!! note + The example below uses the legacy [`@certusone/wormhole-sdk`](https://www.npmjs.com/package/@certusone/wormhole-sdk){target=\_blank}, which is still supported and used in the Relayer Engine but is no longer actively maintained. + + For most use cases, it is recommend to use the latest [`@wormhole-foundation/sdk`](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}. -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol"; +You can also use the Wormhole SDK to poll the Guardian RPC until a signed VAA is ready using the SDK's `getSignedVAAWithRetry` function. -contract MessageReceiver is IWormholeReceiver { - IWormholeRelayer public wormholeRelayer; - address public registrationOwner; +```ts +import { + getSignedVAAWithRetry, + parseVAA, + CHAIN_ID_SOLANA, + CHAIN_ID_ETH, +} from '@certusone/wormhole-sdk'; - // Mapping to store registered senders for each chain - mapping(uint16 => bytes32) public registeredSenders; +const RPC_HOSTS = [ + /* ...*/ +]; - event MessageReceived(string message); - event SourceChainLogged(uint16 sourceChain); +async function getVAA( + emitter: string, + sequence: string, + chainId: number +): Promise { + // Wait for the VAA to be ready and fetch it from the guardian network + const { vaaBytes } = await getSignedVAAWithRetry( + RPC_HOSTS, + chainId, + emitter, + sequence + ); + return vaaBytes; +} - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - registrationOwner = msg.sender; // Set contract deployer as the owner - } +const vaaBytes = await getVAA('INSERT_EMITTER_ADDRESS', 1, CHAIN_ID_ETH); + +``` - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } +Once you have the VAA, the delivery method is chain-dependent. - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } +=== "EVM" - // Update receiveWormholeMessages to include the source address check - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 - ) public payable override isRegisteredSender(sourceChain, sourceAddress) { - require( - msg.sender == address(wormholeRelayer), - "Only the Wormhole relayer can call this function" - ); + On EVM chains, the bytes for the VAA can be passed directly as an argument to an ABI method. - // Decode the payload to extract the message - string memory message = abi.decode(payload, (string)); + ```ts + // Set up eth wallet +const ethProvider = new ethers.providers.StaticJsonRpcProvider( + 'INSERT_RPC_URL' +); +const ethWallet = new ethers.Wallet('INSERT_PRIVATE_KEY', ethProvider); - // Example use of sourceChain for logging - if (sourceChain != 0) { - emit SourceChainLogged(sourceChain); - } +// Create client to interact with our target app +const ethHelloWorld = HelloWorld__factory.connect( + 'INSERT_CONTRACT_ADDRESS', + ethWallet +); - // Emit an event with the received message - emit MessageReceived(message); - } -} +// Invoke the receiveMessage on the ETH contract and wait for confirmation +const receipt = await ethHelloWorld + .receiveMessage(vaaBytes) + .then((tx: ethers.ContractTransaction) => tx.wait()) + .catch((msg: any) => { + console.error(msg); + return null; + }); ``` -## Deploy Contracts +=== "Solana" -This section will guide you through deploying the cross-chain messaging contracts on the Avalanche Fuji and Celo Alfajores Testnets. Follow these steps to get your contracts up and running. + On Solana, the VAA is first posted to the core bridge, and then a custom transaction is prepared to process and validate the VAA. -### Deployment Tools -We use _Foundry_ to deploy our smart contracts. However, you can use any tool you're comfortable with, such as: + ```ts + import { CONTRACTS } from '@certusone/wormhole-sdk'; - - [Remix](https://remix.ethereum.org/){target=\_blank} for a browser-based IDE - - [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#installation){target=\_blank} for a more extensive JavaScript/TypeScript workflow - - [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for a CLI-focused experience with built-in scripting and testing features +export const WORMHOLE_CONTRACTS = CONTRACTS[NETWORK]; +export const CORE_BRIDGE_PID = new PublicKey(WORMHOLE_CONTRACTS.solana.core); + +// First, post the VAA to the core bridge +await postVaaSolana( + connection, + wallet.signTransaction, + CORE_BRIDGE_PID, + wallet.key(), + vaaBytes +); + +const program = createHelloWorldProgramInterface(connection, programId); +const parsed = isBytes(wormholeMessage) + ? parseVaa(wormholeMessage) + : wormholeMessage; + +const ix = program.methods + .receiveMessage([...parsed.hash]) + .accounts({ + payer: new PublicKey(payer), + config: deriveConfigKey(programId), + wormholeProgram: new PublicKey(wormholeProgramId), + posted: derivePostedVaaKey(wormholeProgramId, parsed.hash), + foreignEmitter: deriveForeignEmitterKey(programId, parsed.emitterChain), + received: deriveReceivedKey( + programId, + parsed.emitterChain, + parsed.sequence + ), + }) + .instruction(); + +const transaction = new Transaction().add(ix); +const { blockhash } = await connection.getLatestBlockhash(commitment); +transaction.recentBlockhash = blockhash; +transaction.feePayer = new PublicKey(payerAddress); -The contracts and deployment steps remain the same regardless of your preferred tool. The key is to ensure you have the necessary Testnet funds and are deploying to the right networks. +const signed = await wallet.signTxn(transaction); +const txid = await connection.sendRawTransaction(signed); -### Repository Setup +await connection.confirmTransaction(txid); + ``` +--- END CONTENT --- -To get started with cross-chain messaging using Wormhole, first clone the [GitHub repository](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank}. This repository includes everything you need to deploy, interact, and test the message flow between chains. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-spy/ +--- BEGIN CONTENT --- +--- +title: Run a Spy +description: Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. +--- -This demo focuses on using the scripts, so it's best to take a look at them, starting with `deploySender.ts`, `deployReceiver.ts`, and `sendMessage.ts`. +# Run a Spy -To configure the dependencies properly, run the following command: +## Introduction -```bash -npm install -``` +The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. -The repository includes: +For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. -- Two Solidity contracts: +## How to Start a Spy - - **`MessageSender.sol`** - contract that sends the cross-chain message from Avalanche - - **`MessageReceiver.sol`** - contract that receives the cross-chain message on Celo +To start a Spy locally, run the following Docker command: -- Deployment scripts located in the `script` directory: +=== "Mainnet" - - **`deploySender.ts`** - deploys the `MessageSender` contract to Avalanche - - **`deployReceiver.ts`** - deploys the `MessageReceiver` contract to Celo - - **`sendMessage.ts`** - sends a message from Avalanche to Celo + ```sh + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env mainnet + ``` -- Configuration files and ABI JSON files for easy deployment and interaction: +=== "Testnet" - - **`chains.json`** - configuration file that stores key information for the supported Testnets, including the Wormhole relayer addresses, RPC URLs, and chain IDs. You likely won't need to modify this file unless you're working with different networks + ```sh + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env testnet + ``` - - A dedicated `interfaces` directory inside the `src` folder for TypeScript type definitions: +If you want to run the Spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image. - - **`ChainsConfig.ts`** - defines the types for the `chains.json` configuration file - - **`DeployedContracts.ts`** - contains types for deployed contract addresses and related information - - **`MessageJsons.ts`** - includes types for ABI and bytecode JSONs used by the deployment scripts - - **`index.ts`** - serves as an export aggregator for the interfaces, simplifying imports in other files +Optionally, add the following flags to skip any VAAs with invalid signatures: -### Important Setup Steps +=== "Mainnet" -1. **Add your private key** - create a `.env` file in the root of the project and add your private key: - - ```env - touch .env + ```sh + --ethRPC https://eth.drpc.org + --ethContract 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B ``` - Inside `.env`, add your private key in the following format: +=== "Testnet" - ```env - PRIVATE_KEY=INSERT_PRIVATE_KEY + ```sh + --ethRPC https://sepolia.drpc.org/ + --ethContract 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 ``` -2. **Compile the contracts** - ensure everything is set up correctly by compiling the contracts: +Optionally, add the following flags to prevent unbounded log growth: - ```bash - forge build - ``` +```sh +--log-opt max-size=10m \ +--log-opt max-file=3 +``` -The expected output should be similar to this: +## Subscribe to Filtered VAAs -
-forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
+Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your program) can subscribe to a filtered stream of messages (VAAs). -### Deployment Process +Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. -Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the following key tasks: +!!! note + If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. -1. **Load configuration and contract details** - each script begins by loading the necessary configuration details, such as the network's RPC URL and the contract's ABI and bytecode. This information is essential for deploying the contract to the correct blockchain network +## Data Persistence - === "`chains.json`" +The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. - ```json - { - "chains": [ - { - "description": "Avalanche testnet fuji", - "chainId": 6, - "rpc": "https://api.avax-test.network/ext/bc/C/rpc", - "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", - "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", - "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" - }, - { - "description": "Celo Testnet", - "chainId": 14, - "rpc": "https://alfajores-forno.celo-testnet.org", - "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", - "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", - "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" - } - ] -} - ``` +The persistence layer needs to implement the appropriate interface. For example, you can check out the [Redis interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank} used by the Relayer Engine, a package that implements a client and persistence layer for messages received from a Spy subscription. +--- END CONTENT --- - === "`deploySender.ts`" +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ +--- BEGIN CONTENT --- +--- +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. +categories: Basics +--- - ```typescript - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +# Core Contracts - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); - ``` +## Introduction - === "`deployReceiver.ts`" +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. - ```typescript - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - // Get the Celo Testnet configuration - const celoChain = chains.chains.find((chain) => - chain.description.includes('Celo Testnet') - ); - ``` +## Key Functions - !!! note - The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/){target=\_blank}. +Key functions of the Wormhole Core Contract include the following: -2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - === "`deploySender.ts`" +## How the Core Contract Works - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. - === "`deployReceiver.ts`" +The following describes the role of the Wormhole Core Contract in message transfers: - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -3. **Deploy the contract** - the contract is deployed to the network specified in the configuration. Upon successful deployment, the contract address is returned, which is crucial for interacting with the contract later on +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - === "`deploySender.ts`" +### Message Submission - ```typescript - avalancheChain.wormholeRelayer - ); - await senderContract.waitForDeployment(); - ``` +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - === "`deployReceiver.ts`" +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page - ```typescript - celoChain.wormholeRelayer - ); - await receiverContract.waitForDeployment(); - ``` +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. -4. **Register the `MessageSender` on the target chain** - after you deploy the `MessageReceiver` contract on the Celo Alfajores network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed +### Message Reception - This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - ```typescript - const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; - if (!avalancheSenderAddress) { - throw new Error('Avalanche MessageSender address not found.'); - } +## Multicast - // Define the source chain ID for Avalanche Fuji - const sourceChainId = 6; +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. - // Call setRegisteredSender on the MessageReceiver contract - const tx = await (receiverContract as any).setRegisteredSender( - sourceChainId, - ethers.zeroPadValue(avalancheSenderAddress, 32) - ); - await tx.wait(); - ``` +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -You can find the full code for the `deploySender.ts` and `deployReceiver.ts` below. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -??? code "deploySender.ts" +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. - ```typescript - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { - ChainsConfig, - DeployedContracts, - MessageSenderJson, -} from './interfaces'; +## Next Steps -dotenv.config(); +
+ +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** + + --- + + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. + + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) -async function main(): Promise { - // Load the chain configuration from JSON - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); - if (!avalancheChain) { - throw new Error( - 'Avalanche testnet configuration not found in chains.json.' - ); - } + --- - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - // Load the ABI and bytecode of the MessageSender contract - const messageSenderJson: MessageSenderJson = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - const { abi, bytecode } = messageSenderJson; +
+--- END CONTENT --- - // Create a ContractFactory for MessageSender - const MessageSender = new ethers.ContractFactory(abi, bytecode, wallet); +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- - // Deploy the contract using the Wormhole Relayer address for Avalanche Fuji - const senderContract = await MessageSender.deploy( - avalancheChain.wormholeRelayer - ); - await senderContract.waitForDeployment(); +## Guardian - console.log('MessageSender deployed to:', senderContract.target); // `target` is the address in ethers.js v6 +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - // Update the deployedContracts.json file - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/deployedContracts.json' - ); - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); +Guardians fulfill their role in the messaging protocol as follows: - deployedContracts.avalanche = { - MessageSender: senderContract.target as any, - deployedAt: new Date().toISOString(), - }; +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); -} +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +## Guardian Network -??? code "deployReceiver.ts" +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - ```typescript - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { - ChainsConfig, - DeployedContracts, - MessageReceiverJson, -} from './interfaces'; +The Guardian Network is designed to help Wormhole deliver on five key principles: -dotenv.config(); +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing -async function main(): Promise { - // Load the chain configuration from the JSON file - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +The following sections explore each principle in detail. - // Get the Celo Testnet configuration - const celoChain = chains.chains.find((chain) => - chain.description.includes('Celo Testnet') - ); - if (!celoChain) { - throw new Error('Celo Testnet configuration not found.'); - } +### Decentralization - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(celoChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. - // Load the ABI and bytecode of the MessageReceiver contract - const messageReceiverJson: MessageReceiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/MessageReceiver.sol/MessageReceiver.json' - ), - 'utf8' - ) - ); +Two common approaches to decentralization have notable limitations: - const { abi, bytecode } = messageReceiverJson; +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment - // Create a ContractFactory for MessageReceiver - const MessageReceiver = new ethers.ContractFactory(abi, bytecode, wallet); +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. - // Deploy the contract using the Wormhole Relayer address for Celo Testnet - const receiverContract = await MessageReceiver.deploy( - celoChain.wormholeRelayer - ); - await receiverContract.waitForDeployment(); +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? - console.log('MessageReceiver deployed to:', receiverContract.target); // `target` is the contract address in ethers.js v6 +To answer that, consider these key constraints and design decisions: - // Update the deployedContracts.json file - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/deployedContracts.json' - ); - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants - // Retrieve the address of the MessageSender from the deployedContracts.json file - const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; - if (!avalancheSenderAddress) { - throw new Error('Avalanche MessageSender address not found.'); - } +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. - // Define the source chain ID for Avalanche Fuji - const sourceChainId = 6; +### Modularity - // Call setRegisteredSender on the MessageReceiver contract - const tx = await (receiverContract as any).setRegisteredSender( - sourceChainId, - ethers.zeroPadValue(avalancheSenderAddress, 32) - ); - await tx.wait(); +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - console.log( - `Registered MessageSender (${avalancheSenderAddress}) for Avalanche chain (${sourceChainId})` - ); +### Chain Agnosticism - deployedContracts.celo = { - MessageReceiver: receiverContract.target as any, - deployedAt: new Date().toISOString(), - }; +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); -} +### Scalability -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. -### Deploy the Sender Contract +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -The sender contract will handle quoting and sending messages cross-chain. +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -1. Run the following command to deploy the sender contract: +### Upgradeable - ```bash - npm run deploy:sender - ``` +Wormhole is designed to adapt and evolve in the following ways: -2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\_blank} +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -
-npm run deploy:sender - > wormhole-cross-chain@1.0.0 deploy:sender - > node script/deploySender.ts - MessageSender deployed to: 0xf5c474f335fFf617fA6FD04DCBb17E20ee0cEfb1 - -
+These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. +## Next Steps -### Deploy the Receiver Contract +
-The receiver contract listens for cross-chain messages and logs them when received. +- :octicons-book-16:{ .lg .middle } **Relayers** -1. Deploy the receiver contract with this command: - - ```bash - npm run deploy:receiver - ``` + --- -2. After deployment, note down the contract address. You may check the contract on the [Celo Alfajores Explorer](https://alfajores.celoscan.io/){target=\_blank}. + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -## Send a Cross-Chain Message +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -Now that both the sender and receiver contracts are deployed, let's move on to the next exciting step: sending a cross-chain message from Avalanche Fuji to Celo Alfajores. + --- -In this example, we will use the `sendMessage.ts` script to transmit a message from the sender contract on Avalanche to the receiver contract on Celo. The script uses [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} to interact with the deployed contracts, calculate the cross-chain cost dynamically, and handle the transaction. + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. -Let's break down the script step by step. + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) -1. **Load configuration files** +
+--- END CONTENT --- - 1. **`chains.json`** - contains details about the supported Testnet chains, such as RPC URLs and relayer addresses - 2. **`deployedContracts.json`** - stores the addresses of the deployed sender and receiver contracts. This file is dynamically updated when contracts are deployed, but users can also manually add their own deployed contract addresses if needed +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- - ```typescript - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +# Relayers - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/deployedContracts.json'), - 'utf8' - ) - ); - ``` +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -2. **Configure the provider and signer** - the script first reads the chain configurations and extracts the contract addresses. One essential step in interacting with a blockchain is setting up a _provider_. A provider is your connection to the blockchain network. It allows your script to interact with the blockchain, retrieve data, and send transactions. In this case, we're using a JSON-RPC provider +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - Next, we configure the wallet, which will be used to sign transactions. The wallet is created using the private key and the provider. This ensures that all transactions sent from this wallet are broadcast to the Avalanche Fuji network: - - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +There are three primary types of relayers discussed: - After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it: +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - ```typescript - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); - ``` +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) -3. **Set up the message details** - the next part of the script defines the target chain (Celo) and the target address (the receiver contract on Celo): +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - ```typescript - const targetAddress = deployedContracts.celo.MessageReceiver; - ``` +## Fundamentals - You can customize the message that will be sent across chains: +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - ```typescript - - ``` +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. -4. **Estimate cross-chain cost** - before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function: +Key characteristics of VAAs include: - ```typescript - - ``` +- Public emission from the Guardian Network - This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message. +- Authentication through signatures from the Guardian Network -5. **Send a message** - with everything set up, the message is sent using the `sendMessage` function: +- Verifiability by any entity or any Wormhole Core Contract - ```typescript - targetChain, - targetAddress, - message, - { - value: txCost, - } - ); - ``` +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - After sending, the script waits for the transaction to be confirmed: +Keep in mind the following security considerations around relayers: - ```typescript - - ``` +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -6. **Run the script** - to send the message, run the following command: +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - ```bash - npm run send:message - ``` +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -If everything is set up correctly, the message will be sent from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. You can monitor the transaction and verify that the message was received on Celo using the [Wormhole Explorer](https://wormholescan.io/#/?network=TESTNET){target=\_blank}. +## Client-Side Relaying -The console should output something similar to this: +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -
-npm run send:message - > wormhole-cross-chain@1.0.0 send:message - > node script/sendMessage.ts -Sender Contract Address: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 -Receiver Contract Address: 0x692550997C252cC5044742D1A2BD91E4f4b46D39 -... -Transaction sent, waiting for confirmation... -... -Message sent! Transaction hash: - 0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6 -You may see the transaction status on the Wormhole Explorer: - https://wormholescan.io/#/tx/0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6?network=TESTNET - -
+### Key Features -You can find the full code for the `sendMessage.ts` below. +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -??? code "sendMessage.ts" +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - ```solidity - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { ChainsConfig, DeployedContracts } from './interfaces'; +### Implementation -dotenv.config(); +Users themselves carry out the three steps of the cross-chain process: -async function main(): Promise { - // Load the chain configuration and deployed contract addresses - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +1. Perform an action on chain A - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/deployedContracts.json'), - 'utf8' - ) - ); +2. Retrieve the resulting VAA from the Guardian Network - console.log( - 'Sender Contract Address: ', - deployedContracts.avalanche.MessageSender - ); - console.log( - 'Receiver Contract Address: ', - deployedContracts.celo.MessageReceiver - ); - console.log('...'); +3. Perform an action on chain B using the VAA - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); +### Considerations - if (!avalancheChain) { - throw new Error( - 'Avalanche testnet configuration not found in chains.json.' - ); - } +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); +- Users must sign all required transactions with their own wallet - // Load the ABI of the MessageSender contract - const messageSenderJson = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); +- Users must have funds to pay the transaction fees on every chain involved - const abi = messageSenderJson.abi; +- The user experience may be cumbersome due to the manual steps involved - // Create a contract instance for MessageSender - const MessageSender = new ethers.Contract( - deployedContracts.avalanche.MessageSender, // Automatically use the deployed address - abi, - wallet - ); +## Custom Relayers - // Define the target chain and target address (the Celo receiver contract) - const targetChain = 14; // Wormhole chain ID for Celo Alfajores - const targetAddress = deployedContracts.celo.MessageReceiver; +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - // The message you want to send - const message = 'Hello from Avalanche to Celo!'; +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - // Dynamically quote the cross-chain cost - const txCost = await MessageSender.quoteCrossChainCost(targetChain); +### Key Features - // Send the message (make sure to send enough gas in the transaction) - const tx = await MessageSender.sendMessage( - targetChain, - targetAddress, - message, - { - value: txCost, - } - ); +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - console.log('Transaction sent, waiting for confirmation...'); - await tx.wait(); - console.log('...'); +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - console.log('Message sent! Transaction hash:', tx.hash); - console.log( - `You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/${tx.hash}?network=TESTNET` - ); -} +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience -## Conclusion +### Implementation -You're now fully equipped to build cross-chain contracts using the Wormhole protocol! With this tutorial, you've learned how to: +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. -- Deploy sender and receiver contracts on different Testnets -- Send a cross-chain message from one blockchain to another -- Monitor the status of your cross-chain transactions using the Wormhole Explorer and Wormhole-Solidity-SDK ---- END CONTENT --- +### Considerations -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-token-contracts/ ---- BEGIN CONTENT --- ---- -title: Cross-Chain Token Transfers -description: Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. ---- +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." -# Create Cross-Chain Token Transfer Contracts +- Development work and hosting of relayers are required -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees -## Introduction +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -In this tutorial, you'll learn how to create a simple cross-chain token transfer system using the Wormhole protocol via the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. We'll guide you through building and deploying smart contracts that enable seamless token transfers of IERC-20 tokens between blockchains. Whether you're a developer looking to explore cross-chain applications or just interested in the Wormhole protocol, this guide will help you understand the fundamentals. +## Wormhole Relayers -By the end of this tutorial, you'll have a working cross-chain token transfer system built with the powerful tools provided by the Wormhole Solidity SDK, which you can further customize and integrate into your projects. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -## Prerequisites +### Key Features -Before you begin, ensure you have the following: +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts -- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees -- [USDC Testnet](https://faucet.circle.com/){target=\_blank} tokens on Avalanche-Fuji or/and Celo-Alfajores for cross-chain transfer -- Wallet private key +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -## Valid Tokens for Transfer +### Implementation -It's important to note that this tutorial leverages [Wormhole's TokenBridge](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/TokenBridge.sol){target=\_blank} to transfer tokens between chains. So, the tokens you'd like to transfer must have an attestation on the `TokenBridge` contract of the target blockchain. +The Wormhole relayer integration involves two key steps: -To simplify this process, we've included a tool for verifying if a token has an attestation on the target chain. This tool uses the [`wrappedAsset`](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/BridgeGetters.sol#L50-L52){target=\_blank} function from the `TokenBridge` contract. If the token has an attestation, the `wrappedAsset` function returns the address of the wrapped token on the target chain; otherwise, it returns the zero address. +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract -???- tip "Check Token Attestation" - 1. Clone the [repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} and navigate to the project directory: - ```bash - git clone https://github.com/wormhole-foundation/demo-cross-chain-token-transfer.git - cd cross-chain-token-transfers - ``` - 2. Install the dependencies: - ```bash - npm install - ``` - - 3. Run the script to check token attestation: - ```bash - npm run verify - ``` +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA - 4. Follow the prompts: +### Considerations - 1. Enter the RPC URL of the target chain - 2. Enter the `TokenBridge` contract address on the target chain - 3. Enter the token contract address on the source chain - 4. Enter the source chain ID +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. - 5. The expected output when the token has an attestation: - -
-npm run verify - > cross-chain-token-transfer@1.0.0 verify - > npx ts-node script/check-attestation.ts - - Enter the TARGET chain RPC URL: https://alfajores-forno.celo-testnet.org - Enter the Token Bridge contract address on the TARGET chain: 0x05...E153 - Enter the token contract address on the SOURCE chain: 0x54...bc65 - Enter the SOURCE chain ID: 6 - The token is attested on the target chain. Wrapped token address: 0xDDB349c976cA2C873644F21f594767Eb5390C831 - -
- - Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process. +- All computations are performed on-chain -## Project Setup +- Potentially less gas-efficient compared to custom relayers -Let's start by initializing a new Foundry project. This will set up a basic structure for our smart contracts. +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted -1. Open your terminal and run the following command to initialize a new Foundry project: - - ```bash - forge init cross-chain-token-transfers - ``` +- Support may not be available for all chains - This will create a new directory named `cross-chain-token-transfers` with a basic project structure. This also initializes a new `git` repository. +## Next Steps -2. Navigate into the newly created project directory: +
- ```bash - cd cross-chain-token-transfers - ``` +- :octicons-book-16:{ .lg .middle } **Spy** -3. Install the Wormhole Solidity SDK: + --- - ```bash - forge install wormhole-foundation/wormhole-solidity-sdk - ``` + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - To ease development, we'll use the Wormhole Solidity SDK, which provides useful helpers for cross-chain development. - This SDK includes the `TokenSender` and `TokenReceiver` abstract classes, which simplify sending and receiving tokens across chains. + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) -## Build Cross-Chain Contracts +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** -In this section, we'll build two smart contracts to send tokens from a source chain and receive them on a target chain. These contracts will interact with the Wormhole protocol to facilitate secure and seamless cross-chain token transfers. + --- -At a high level, our contracts will: + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -1. Send tokens from one blockchain to another using the Wormhole protocol -2. Receive and process the tokens on the target chain, ensuring they are correctly transferred to the intended recipient + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) -Before diving into the contract implementation steps, let’s first break down the key parts of the contracts. +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** -### Sender Contract: CrossChainSender + --- -The `CrossChainSender` contract calculates the cost of sending tokens across chains and then facilitates the actual token transfer. + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -Let's start writing the `CrossChainSender` contract: + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -1. Create a new file named `CrossChainSender.sol` in the `/src` directory: - - ```bash - touch src/CrossChainSender.sol - ``` +
+--- END CONTENT --- -2. Open the file. First, we'll start with the imports and the contract setup: +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- - ```solidity - pragma solidity ^0.8.13; +# Spy -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. -contract CrossChainSender is TokenSender { - uint256 constant GAS_LIMIT = 250_000; +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - - ``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. - This sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. +## Key Features - With the contract structure in place, define the following functions within its body to enable multichain token transfers. +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -3. Next, let's add a function that estimates the cost of sending tokens across chains: +## Integrator Use Case - ```solidity - uint16 targetChain - ) public view returns (uint256 cost) { - uint256 deliveryCost; - (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. - cost = deliveryCost + wormhole.messageFee(); - } - ``` +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. - This function, `quoteCrossChainDeposit`, helps calculate the cost of transferring tokens to a different chain. It factors in the delivery cost and the cost of publishing a message via the Wormhole protocol. +## Observable Message Categories -4. Finally, we'll add the function that sends the tokens across chains: +A Spy can access the following categories of messages shared over the gossip protocol: - ```solidity - uint16 targetChain, - address targetReceiver, - address recipient, - uint256 amount, - address token - ) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must equal quoteCrossChainDeposit(targetChain)" - ); +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - IERC20(token).transferFrom(msg.sender, address(this), amount); + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification - bytes memory payload = abi.encode(recipient); +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - sendTokenWithPayloadToEvm( - targetChain, - targetReceiver, - payload, - 0, - GAS_LIMIT, - token, - amount - ); - } - ``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events - This `sendCrossChainDeposit` function is where the actual token transfer happens. It sends the tokens to the recipient on the target chain using the Wormhole protocol. +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -Here’s a breakdown of what happens in each step of the `sendCrossChainDeposit` function: + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network -1. **Cost calculation** - the function starts by calculating the cost of the cross-chain transfer using `quoteCrossChainDeposit`(`targetChain`). This cost includes both the delivery fee and the Wormhole message fee. The `sendCrossChainDeposit` function then checks that the user has sent the correct amount of Ether to cover this cost (`msg.value`) +## Additional Resources -2. **Token transfer to contract** - the next step is to transfer the specified amount of tokens from the user to the contract itself using `IERC-20(token).transferFrom(msg.sender, address(this), amount)`. This ensures that the contract has custody of the tokens before initiating the cross-chain transfer +
-3. **Payload encoding** - The recipient's address on the target chain is encoded into a payload using `abi.encode(recipient)`. This payload will be sent along with the token transfer, so the target contract knows who should receive the tokens on the destination chain +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -4. **Cross-chain transfer** - the `sendTokenWithPayloadToEvm` function is called to initiate the cross-chain token transfer. This function: - - Specifies the `targetChain` (the Wormhole chain ID of the destination blockchain). - - Sends the `targetReceiver` contract address on the target chain that will receive the tokens. - - Attaches the payload containing the recipient's address. - - Sets the `GAS_LIMIT` for the transaction. - - Passes the token `address` and `amount` to transfer. + --- - This triggers the Wormhole protocol to handle the cross-chain messaging and token transfer, ensuring the tokens and payload reach the correct destination on the target chain. + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. -You can find the complete code for the `CrossChainSender.sol` below. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -??? code "MessageSender.sol" +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; + --- -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. -contract CrossChainSender is TokenSender { - uint256 constant GAS_LIMIT = 250_000; + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** - // Function to get the estimated cost for cross-chain deposit - function quoteCrossChainDeposit( - uint16 targetChain - ) public view returns (uint256 cost) { - uint256 deliveryCost; - (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); + --- - cost = deliveryCost + wormhole.messageFee(); - } + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - // Function to send tokens and payload across chains - function sendCrossChainDeposit( - uint16 targetChain, - address targetReceiver, - address recipient, - uint256 amount, - address token - ) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must equal quoteCrossChainDeposit(targetChain)" - ); + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) - IERC20(token).transferFrom(msg.sender, address(this), amount); +
- bytes memory payload = abi.encode(recipient); +## Next Steps - sendTokenWithPayloadToEvm( - targetChain, - targetReceiver, - payload, - 0, - GAS_LIMIT, - token, - amount - ); - } -} - ``` +
-### Receiver Contract: CrossChainReceiver +- :octicons-code-16:{ .lg .middle } **Run a Spy** -The `CrossChainReceiver` contract is designed to handle the receipt of tokens and payloads from another blockchain. It ensures that the tokens are correctly transferred to the designated recipient on the receiving chain. + --- -Let's start writing the `CrossChainReceiver` contract: + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). -1. Create a new file named `CrossChainReceiver.sol` in the `/src` directory: + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} + +- :octicons-code-16:{ .lg .middle } **Use Queries** + + --- + + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - ```bash - touch src/CrossChainReceiver.sol - ``` + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) -2. Open the file. First, we'll start with the imports and the contract setup: +
+--- END CONTENT --- - ```solidity - pragma solidity ^0.8.13; +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +--- BEGIN CONTENT --- +--- +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics +--- -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +# Verified Action Approvals -contract CrossChainReceiver is TokenReceiver { - // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - - ``` +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. - Similar to the `CrossChainSender` contract, this sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. -3. Next, let's add a function inside the contract to handle receiving the payload and tokens: +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. - ```solidity - bytes memory payload, - TokenReceived[] memory receivedTokens, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 // deliveryHash - ) - internal - override - onlyWormholeRelayer - isRegisteredSender(sourceChain, sourceAddress) - { - require(receivedTokens.length == 1, "Expected 1 token transfer"); +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. - // Decode the recipient address from the payload - address recipient = abi.decode(payload, (address)); +## VAA Format - // Transfer the received tokens to the intended recipient - IERC20(receivedTokens[0].tokenAddress).transfer( - recipient, - receivedTokens[0].amount - ); - } - ``` +The basic VAA consists of header and body components described as follows: - This `receivePayloadAndTokens` function processes the tokens and payload sent from another chain, decodes the recipient address, and transfers the tokens to them using the Wormhole protocol. This function also validates the emitter (`sourceAddress`) to ensure the message comes from a trusted sender. +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures - This function ensures that: + Where each `signature` is: - - It only processes one token transfer at a time - - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract - - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. +- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -??? tip "Understanding the `TokenReceived` Struct" +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level - Let’s delve into the fields provided to us in the `TokenReceived` struct: +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. - ```solidity - struct TokenReceived { - bytes32 tokenHomeAddress; - uint16 tokenHomeChain; - address tokenAddress; - uint256 amount; - uint256 amountNormalized; -} - ``` +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. - - **`tokenHomeAddress`** - the original address of the token on its native chain. This is the same as the token field in the call to `sendTokenWithPayloadToEvm` unless the original token sent is a Wormhole-wrapped token. In that case, this will be the address of the original version of the token (on its native chain) in Wormhole address format (left-padded with 12 zeros) +## Consistency and Finality - - **`tokenHomeChain`** - the Wormhole chain ID corresponding to the home address above. This will typically be the source chain unless the original token sent is a Wormhole-wrapped asset, which will be the chain of the unwrapped version of the token +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. - - **`tokenAddress`** - the address of the IERC-20 token on the target chain that has been transferred to this contract. If `tokenHomeChain` equals the target chain, this will be the same as `tokenHomeAddress`; otherwise, it will be the Wormhole-wrapped version of the token sent +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. - - **`amount`** - the token amount sent to you with the same units as the original token. Since `TokenBridge` only sends with eight decimals of precision, if your token has 18 decimals, this will be the "amount" you sent, rounded down to the nearest multiple of 10^10 +## Signatures - - **`amountNormalized`** - the amount of token divided by (1 if decimals ≤ 8, else 10^(decimals - 8)) +The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -You can find the complete code for the `CrossChainReceiver.sol` contract below: +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` -??? code "CrossChainReceiver.sol" +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; +## Payload Types -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -contract CrossChainReceiver is TokenReceiver { - // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract +### Token Transfer - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - // Function to receive the cross-chain payload and tokens with emitter validation - function receivePayloadAndTokens( - bytes memory payload, - TokenReceived[] memory receivedTokens, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 // deliveryHash - ) - internal - override - onlyWormholeRelayer - isRegisteredSender(sourceChain, sourceAddress) - { - require(receivedTokens.length == 1, "Expected 1 token transfer"); +Transferring tokens from the sending chain to the destination chain requires the following steps: - // Decode the recipient address from the payload - address recipient = abi.decode(payload, (address)); +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain - // Transfer the received tokens to the intended recipient - IERC20(receivedTokens[0].tokenAddress).transfer( - recipient, - receivedTokens[0].amount - ); - } -} - ``` +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: -## Deploy the Contracts +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -Now that you've written the `CrossChainSender` and `CrossChainReceiver` contracts, it's time to deploy them to your chosen networks. +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. -1. **Set up deployment configuration** - before deploying, you must configure the networks and the deployment environment. This information is stored in a configuration file +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - 1. Create a directory named deploy-config in the root of your project: +### Attestation - ```bash - mkdir deploy-config - ``` +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - 2. Create a `config.json` file in the `deploy-config` directory: +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - ```bash - touch deploy-config/config.json - ``` +The message format for token attestation is as follows: - 3. Open the `config.json` file and add the following configuration: +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset - ```json - { - "chains": [ - { - "description": "Avalanche testnet fuji", - "chainId": 6, - "rpc": "https://api.avax-test.network/ext/bc/C/rpc", - "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", - "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", - "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" - }, - { - "description": "Celo Testnet", - "chainId": 14, - "rpc": "https://alfajores-forno.celo-testnet.org", - "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", - "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", - "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" - } - ] -} - ``` +#### Attestation Tips - This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. +Be aware of the following considerations when working with attestations: - For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters - !!! note - You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes - 4. Create a `contracts.json` file in the `deploy-config` directory: +- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm - ```bash - echo '{}' > deploy-config/contracts.json - ``` +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 - This file can be left blank initially. It will be automatically updated with the deployed contract addresses after a successful deployment +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -2. **Set up your Node.js environment** - you'll need to set up your Node.js environment to run the deployment script +### Token Transfer with Message - 1. Initialize a Node.js project: +The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: - ```bash - npm init -y - ``` - - 2. Install the necessary dependencies: +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior - ```bash - npm install ethers dotenv readline-sync @types/readline-sync - ``` +This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: - These dependencies are required for the deployment script to work properly. +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific -3. **Compile your smart contracts** - compile your smart contracts using Foundry. This ensures that your contracts are up-to-date and ready for deployment +### Governance - - Run the following command to compile your contracts: +Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). - ```bash - forge build - ``` +#### Action Structure - This will generate the necessary ABI and bytecode files in a directory named `/out`. +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: - The expected output should be similar to this: +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action -
-forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
+Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. -4. **Write the deployment script** - you’ll need a script to automate the deployment of your contracts. Let’s create the deployment script +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` - 1. Create a new file named `deploy.ts` in the `/script` directory: +#### Actions - ```bash - touch script/deploy.ts - ``` +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: - 2. Open the file and load imports and configuration: +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} - ```typescript - import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +## Lifetime of a Message -dotenv.config(); - ``` +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. - Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal. +With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. - 3. Define interfaces to use for chain configuration and contract deployment: +1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step - ```typescript - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} - ``` +## Next Steps - These interfaces define the structure of the chain configuration and the contract deployment details. +
- 4. Load and select the chains for deployment: +- :octicons-book-16:{ .lg .middle } **Guardians** - ```typescript - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} + --- -function selectChain( - chains: ChainConfig[], - role: 'source' | 'target' -): ChainConfig { - console.log(`\nSelect the ${role.toUpperCase()} chain:`); - chains.forEach((chain, index) => { - console.log(`${index + 1}: ${chain.description}`); - }); + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - const chainIndex = - readlineSync.questionInt( - `\nEnter the number for the ${role.toUpperCase()} chain: ` - ) - 1; - return chains[chainIndex]; -} - ``` + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - The `loadConfig` function reads the chain configuration from the `config.json` file, and the `selectChain` function allows the user to choose the source and target chains for deployment interactively. The user is prompted in the terminal to select which chains to use, making the process interactive and user-friendly. +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** - 5. Define the main function for deployment and load the chain configuration: + --- - ```typescript - const chains = loadConfig(); + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - const sourceChain = selectChain(chains, 'source'); - const targetChain = selectChain(chains, 'target'); - ``` + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) - - The `main` function is the entry point for the deployment script - - We then call the `loadConfig` function we previously defined to load the chain configuration from the `config.json` file +
+--- END CONTENT --- - 6. Set up provider and wallet: - - ```typescript - const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); - ``` - - The scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction on the source chain. +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- - 7. Read the compiled contracts: +# Introduction to Wormhole - ```typescript - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); - ``` +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. - - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract - - The file is in the `../out/` directory, which contains the ABI (Application Binary Interface) and bytecode generated during contract compilation - - It uses the `fs.readFileSync` function to read the file and `JSON.parse` to convert the file contents (in JSON format) into a JavaScript object +Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - 8. Extract the contract ABI and bytecode: +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - ```typescript - const bytecode = senderJson.bytecode; - ``` +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - - **ABI (Application Binary Interface)** - defines the structure of the contract’s functions, events, and data types, allowing the front end to interact with the contract on the blockchain - - **Bytecode** - this is the compiled machine code that will be deployed to the blockchain to create the contract +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - 9. Create the Contract Factory: +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - ```typescript - abi, - bytecode, - wallet - ); - ``` +This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. - - **`ethers.ContractFactory`** - creates a new contract factory using the ABI, bytecode, and a wallet (representing the signer). The contract factory is responsible for deploying instances of the contract to the blockchain - - This is a crucial step for deploying the contract since the factory will create and deploy the `CrossChainSender` contract +## What Problems Does Wormhole Solve? - 10. Deploy the `CrossChainSender` and `CrossChainReceiver` contracts: +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. - === "`CrossChainSender`" - ```typescript - const senderContract = await CrossChainSenderFactory.deploy( - sourceChain.wormholeRelayer, - sourceChain.tokenBridge, - sourceChain.wormhole - ); - await senderContract.waitForDeployment(); - ``` +Critical problems Wormhole addresses include: - === "`CrossChainReceiver`" - ```typescript - process.env.PRIVATE_KEY!, - targetProvider - ); - const receiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainReceiver.sol/CrossChainReceiver.json' - ), - 'utf8' - ) - ); - const CrossChainReceiverFactory = new ethers.ContractFactory( - receiverJson.abi, - receiverJson.bytecode, - targetWallet - ); +- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions - const receiverContract = await CrossChainReceiverFactory.deploy( - targetChain.wormholeRelayer, - targetChain.tokenBridge, - targetChain.wormhole - ); - await receiverContract.waitForDeployment(); - ``` +## What Does Wormhole Offer? - Both functions deploy the respective contracts to the selected chains. +Wormhole provides a suite of tools and protocols that support a wide range of use cases: - For the `CrossChainReceiver` contract: +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently - - It defines the wallet related to the target chain - - The logic reads the compiled ABI and bytecode from the JSON file generated during compilation - - It creates a new contract factory using the ABI, bytecode, and wallet - - It deploys the contract to the selected chain passing in the Wormhole Relayer, `TokenBridge`, and Wormhole addresses +## What Isn't Wormhole? - 11. Save the deployed contract addresses: +- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge - === "`senderAddress`" - ```typescript - console.log( - `CrossChainSender on ${sourceChain.description}: ${senderAddress}` - ); - ``` +## Use Cases of Wormhole - === "`receiverAddress`" - ```typescript - console.log( - `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` - ); - ``` +Consider the following examples of potential applications enabled by Wormhole: - You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference. +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum - 12. Register the `CrossChainSender` address on the target chain: +## Explore - ```typescript - receiverAddress, - receiverJson.abi, - targetWallet - ); +Discover more about the Wormhole ecosystem, components, and protocols: - const tx = await CrossChainReceiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) - ); +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole - await tx.wait(); - ``` +## Demos - After you deploy the `CrossChainReceiver` contract on the target network, the sender contract address from the source chain needs to be registered. This ensures that only messages from the registered `CrossChainSender` contract are processed. +Demos offer more realistic implementations than tutorials: - This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `CrossChainReceiver` contract. +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs - 13. Save the deployment details: + - if (fs.existsSync(deployedContractsPath)) { - deployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); - } +!!! note + Wormhole Integration Complete? - // Update the contracts.json file: - // If a contract already exists on a chain, update its address; otherwise, add a new entry. - if (!deployedContracts[sourceChain.chainId]) { - deployedContracts[sourceChain.chainId] = { - networkName: sourceChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[sourceChain.chainId].CrossChainSender = - senderAddress.toString(); - deployedContracts[sourceChain.chainId].deployedAt = - new Date().toISOString(); + Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! - if (!deployedContracts[targetChain.chainId]) { - deployedContracts[targetChain.chainId] = { - networkName: targetChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[targetChain.chainId].CrossChainReceiver = - receiverAddress.toString(); - deployedContracts[targetChain.chainId].deployedAt = - new Date().toISOString(); + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** - // Save the updated contracts.json file - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); - ``` - - Add your desired logic to save the deployed contract addresses in a JSON file (or another format). This will be important later when transferring tokens, as you'll need these addresses to interact with the deployed contracts. +## Supported Blockchains - 14. Handle errors and finalize the script: +Wormhole supports a growing number of blockchains. - ```typescript - if (error.code === 'INSUFFICIENT_FUNDS') { - console.error( - 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' - ); - } else { - console.error('An unexpected error occurred:', error.message); - } - process.exit(1); - } -} + + +
-main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` +### EVM - The try-catch block wraps the deployment logic to catch any errors that may occur. +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :x: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - - If the error is due to insufficient funds, it logs a clear message about needing more gas fees - - For any other errors, it logs the specific error message to help with debugging +### SVM - The `process.exit(1)` ensures that the script exits with a failure status code if any error occurs. +| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - You can find the full code for the `deploy.ts` file below: +### AVM - ??? code "deploy.ts" +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - ```solidity - import { BytesLike, ethers } from 'ethers'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +### CosmWasm -dotenv.config(); +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +### Move VM -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -function loadConfig(): ChainConfig[] { - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +### NEAR VM -function selectChain( - chains: ChainConfig[], - role: 'source' | 'target' -): ChainConfig { - console.log(`\nSelect the ${role.toUpperCase()} chain:`); - chains.forEach((chain, index) => { - console.log(`${index + 1}: ${chain.description}`); - }); +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - const chainIndex = - readlineSync.questionInt( - `\nEnter the number for the ${role.toUpperCase()} chain: ` - ) - 1; - return chains[chainIndex]; -} +### Sui Move VM -async function main() { - const chains = loadConfig(); +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ +--- END CONTENT --- - const sourceChain = selectChain(chains, 'source'); - const targetChain = selectChain(chains, 'target'); +Doc-Content: https://wormhole.com/docs/protocol/security/ +--- BEGIN CONTENT --- +--- +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +categories: Basics +--- - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); +# Security - const senderJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +## Core Security Assumptions - const abi = senderJson.abi; - const bytecode = senderJson.bytecode; +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. - const CrossChainSenderFactory = new ethers.ContractFactory( - abi, - bytecode, - wallet - ); +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem - try { - const senderContract = await CrossChainSenderFactory.deploy( - sourceChain.wormholeRelayer, - sourceChain.tokenBridge, - sourceChain.wormhole - ); - await senderContract.waitForDeployment(); +In summary: - // Safely access the deployed contract's address - const senderAddress = (senderContract as ethers.Contract).target; - console.log( - `CrossChainSender on ${sourceChain.description}: ${senderAddress}` - ); +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit - const targetWallet = new ethers.Wallet( - process.env.PRIVATE_KEY!, - targetProvider - ); - const receiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainReceiver.sol/CrossChainReceiver.json' - ), - 'utf8' - ) - ); - const CrossChainReceiverFactory = new ethers.ContractFactory( - receiverJson.abi, - receiverJson.bytecode, - targetWallet - ); +Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. + +## Guardian Network - const receiverContract = await CrossChainReceiverFactory.deploy( - targetChain.wormholeRelayer, - targetChain.tokenBridge, - targetChain.wormhole - ); - await receiverContract.waitForDeployment(); +Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. - // Safely access the deployed contract's address - const receiverAddress = (receiverContract as ethers.Contract).target; - console.log( - `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` - ); +### Governance - // Register the sender contract in the receiver contract - console.log( - `Registering CrossChainSender (${senderAddress}) as a valid sender in CrossChainReceiver (${receiverAddress})...` - ); +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. - const CrossChainReceiverContract = new ethers.Contract( - receiverAddress, - receiverJson.abi, - targetWallet - ); +This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. - const tx = await CrossChainReceiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) - ); +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. - await tx.wait(); - console.log( - `CrossChainSender registered as a valid sender on ${targetChain.description}` - ); +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. - // Load existing deployed contract addresses from contracts.json - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - let deployedContracts: DeployedContracts = {}; +Via governance, the Guardians can: - if (fs.existsSync(deployedContractsPath)) { - deployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); - } +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations - // Update the contracts.json file: - // If a contract already exists on a chain, update its address; otherwise, add a new entry. - if (!deployedContracts[sourceChain.chainId]) { - deployedContracts[sourceChain.chainId] = { - networkName: sourceChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[sourceChain.chainId].CrossChainSender = - senderAddress.toString(); - deployedContracts[sourceChain.chainId].deployedAt = - new Date().toISOString(); +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. - if (!deployedContracts[targetChain.chainId]) { - deployedContracts[targetChain.chainId] = { - networkName: targetChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[targetChain.chainId].CrossChainReceiver = - receiverAddress.toString(); - deployedContracts[targetChain.chainId].deployedAt = - new Date().toISOString(); +## Monitoring - // Save the updated contracts.json file - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); - } catch (error: any) { - if (error.code === 'INSUFFICIENT_FUNDS') { - console.error( - 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' - ); - } else { - console.error('An unexpected error occurred:', error.message); - } - process.exit(1); - } -} +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. -main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. -5. **Add your private key** - you'll need to provide your private key. It allows your deployment script to sign the transactions that deploy the smart contracts to the blockchain. Without it, the script won't be able to interact with the blockchain on your behalf +Guardians monitor: - Create a `.env` file in the root of the project and add your private key: +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators - ```bash - touch .env - ``` +## Asset Layer Protections - Inside `.env`, add your private key in the following format: +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. - ```env - PRIVATE_KEY=INSERT_PRIVATE_KEY - ``` - -6. **Run the deployment script** +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. - 1. Open a terminal and run the following command: +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. - ```bash - npx ts-node script/deploy.ts - ``` +## Open Source - This will execute the deployment script, deploying both contracts to the selected chains. +Wormhole builds in the open and is always open source. - 2. Check the deployment output: +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - - You will see the deployed contract addresses printed in the terminal if successful. The `contracts.json` file will be updated with these addresses - - If you encounter an error, the script will provide feedback, such as insufficient funds for gas +## Audits -If you followed the logic provided in the full code above, your terminal output should look something like this: +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -
-npx ts-node deploy.ts - > cross-chain-token-transfer@1.0.0 deploy - > npx ts-node script/deploy.ts - Select the SOURCE chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the SOURCE chain: 1 - - Select the TARGET chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the TARGET chain: 2 - CrossChainSender Avalanche testnet fuji: 0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3 - CrossChainReceiver Celo Testnet: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 - - Registering CrossChainSender (0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3) as a valid sender in CrossChainReceiver (0xD720BFF42a0960cfF1118454A907a44dB358f2b1)... - - CrossChainSender registered as a valid sender on Celo Testnet - -
+- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. -## Transfer Tokens Across Chains +## Bug Bounties -### Quick Recap +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -Up to this point, you've set up a new Solidity project using Foundry, developed two key contracts (`CrossChainSender` and `CrossChainReceiver`), and created a deployment script to deploy these contracts to different blockchain networks. The deployment script also saves the new contract addresses for easy reference. With everything in place, it's time to transfer tokens using the deployed contracts. +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. -In this step, you'll write a script to transfer tokens across chains using the `CrossChainSender` and `CrossChainReceiver` contracts you deployed earlier. This script will interact with the contracts and facilitate the cross-chain token transfer. +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. -### Transfer Script +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. -1. **Set up the transfer script** +## Learn More - 1. Create a new file named `transfer.ts` in the `/script` directory: +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- - ```bash - touch script/transfer.ts - ``` +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - 2. Open the file. Start with the necessary imports, interfaces and configurations: +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ +--- BEGIN CONTENT --- +--- +title: Solidity SDK +description: How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. +categories: Solidity-SDK +--- - ```typescript - import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +# Solidity SDK -dotenv.config(); +## Introduction -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains. -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} - ``` +By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides: - These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input. + - **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure + - **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain + - **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement + - **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments - 3. Load configuration and contracts: +These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains. +This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing. - ```typescript - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +## Installation -function loadDeployedContracts(): DeployedContracts { - const contractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - if ( - !fs.existsSync(contractsPath) || - fs.readFileSync(contractsPath, 'utf8').trim() === '' - ) { - console.error( - 'No contracts found. Please deploy contracts first before transferring tokens.' - ); - process.exit(1); - } - return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); -} - ``` +To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk@v0.1.0 +``` + +When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file: - These functions load the network and contract details that were saved during deployment. +```toml +evm_version = "paris" +``` - 4. Allow users to select source and target chains: +This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades. - Refer to the deployed contracts and create logic as desired. In our example, we made this process interactive, allowing users to select the source and target chains from all the historically deployed contracts. This interactive approach helps ensure the correct chains are selected for the token transfer. +## Key Considerations - ```typescript - chainId: number; - networkName: string; -} { - const sourceOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainSender - ); +Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind: - if (sourceOptions.length === 0) { - console.error('No source chains available with CrossChainSender deployed.'); - process.exit(1); - } + - **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes + - **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries + - **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments - console.log('\nSelect the source chain:'); - sourceOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +## Concepts and Components - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; - return { - chainId: Number(sourceOptions[selectedIndex][0]), - networkName: sourceOptions[selectedIndex][1].networkName, - }; -} +The Wormhole Solidity SDK consists of key components that streamline cross-chain communication, allowing developers to securely and efficiently interact with Wormhole’s infrastructure. Below are the critical concepts and contracts you'll encounter when working with the SDK. -function selectTargetChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const targetOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainReceiver - ); +### Cross-Chain Messaging with the Wormhole Relayer SDK - if (targetOptions.length === 0) { - console.error( - 'No target chains available with CrossChainReceiver deployed.' - ); - process.exit(1); - } +The [`WormholeRelayerSDK.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} contract simplifies cross-chain messaging and asset transfers by integrating several necessary modules, including the Wormhole relayer. By automating message delivery between chains, the Wormhole relayer removes the need for developers to manage relayer infrastructure or handle gas on the target chain. Delivery providers handle the message payload, ensuring secure and efficient communication. - console.log('\nSelect the target chain:'); - targetOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +You can refer to the [Wormhole relayer documentation](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} for more details. - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; - return { - chainId: Number(targetOptions[selectedIndex][0]), - networkName: targetOptions[selectedIndex][1].networkName, - }; -} - ``` +Key modules in the SDK include: -2. **Implement the token transfer logic** + - **`Base.sol`** - the core module for cross-chain messaging. It provides utility functions like `onlyWormholeRelayer()` and `setRegisteredSender()`, ensuring that only messages from trusted relayers are processed - 1. Start the `main` function: - - ```typescript - const chains = loadConfig(); - const deployedContracts = loadDeployedContracts(); + - **`TokenBase.sol`** - this module extends the base messaging functionality to support cross-chain token transfers. It includes utilities for securely sending and receiving tokens between EVM-compatible chains - // Select the source chain (only show chains with CrossChainSender deployed) - const { chainId: sourceChainId, networkName: sourceNetworkName } = - selectSourceChain(deployedContracts); - const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; + - **`CCTPBase.sol`** - designed for Circle’s Cross-Chain Transfer Protocol, this module manages asset transfers such as USDC between chains. It includes functionalities for both sending and receiving CCTP-based assets - // Select the target chain (only show chains with CrossChainReceiver deployed) - const { chainId: targetChainId, networkName: targetNetworkName } = - selectTargetChain(deployedContracts); - const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; + - **`CCTPAndTokenBase.sol`** - a combined module that supports token and CCTP-based asset transfers in a single implementation. This module simplifies development for applications needing to handle both types of transfers - // Set up providers and wallets - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); +The Wormhole Solidity SDK offers a unified framework for cross-chain communication. Developers can select specific modules based on their application’s requirements, whether for messaging, token transfers, or CCTP. Each module includes built-in security measures, ensuring that only authorized senders or relayers are accepted, thereby protecting the application from unauthorized interactions. - // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) - const CrossChainSenderArtifact = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +Please refer to the complete `WormholeRelayerSDK.sol` file below for further details. - const abi = CrossChainSenderArtifact.abi; +???- code "`WormholeRelayerSDK.sol`" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; - // Create the contract instance using the full ABI - const CrossChainSender = new ethers.Contract( - deployedContracts[sourceChainId].CrossChainSender!, - abi, - wallet - ); - ``` - - The `main` function is where the token transfer logic will reside. It loads the chain and contract details, sets up the wallet and provider, and loads the `CrossChainSender` contract. +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/constants/Chains.sol"; +import "wormhole-sdk/Utils.sol"; - 2. Ask the user for token transfer details: +import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; +import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; +import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; +import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; + ``` - You'll now ask the user for the token contract address, the recipient address on the target chain, and the amount of tokens to transfer. +### Base Contract Overview - ```typescript - 'Enter the token contract address: ' - ); - const recipientAddress = readlineSync.question( - 'Enter the recipient address on the target chain: ' - ); +The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/Base.sol){target=\_blank} contract is a core part of the Wormhole Solidity SDK, providing essential helper functions and modifiers for managing cross-chain messages securely via the Wormhole Relayer. It handles sender registration and message validation, ensuring only authorized senders from specific chains can send messages. - // Get the token contract - const tokenContractDecimals = new ethers.Contract( - tokenAddress, - [ - 'function decimals() view returns (uint8)', - 'function approve(address spender, uint256 amount) public returns (bool)', - ], - wallet - ); + - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions - // Fetch the token decimals - const decimals = await tokenContractDecimals.decimals(); + ```solidity + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } + ``` - // Get the amount from the user, then parse it according to the token's decimals - const amount = ethers.parseUnits( - readlineSync.question('Enter the amount of tokens to transfer: '), - decimals - ); - ``` + - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources - This section of the script prompts the user for the token contract address and the recipient's address, fetches the token's decimal value, and parses the amount accordingly. + ```solidity + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } + ``` - 3. Initiate the transfer: +These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. - Finally, initiate the cross-chain transfer and log the details. +???- code "`Base.sol`" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; - ```typescript - // Approve the CrossChainSender contract to transfer tokens on behalf of the user - const tokenContract = new ethers.Contract( - tokenAddress, - ['function approve(address spender, uint256 amount) public returns (bool)'], - wallet - ); +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/interfaces/IWormhole.sol"; +import "wormhole-sdk/Utils.sol"; - const approveTx = await tokenContract.approve( - deployedContracts[sourceChainId].CrossChainSender!, - amount - ); - await approveTx.wait(); - console.log(`Approved tokens for cross-chain transfer.`); +abstract contract Base { + IWormholeRelayer public immutable wormholeRelayer; + IWormhole public immutable wormhole; - // Initiate the cross-chain transfer - const transferTx = await CrossChainSender.sendCrossChainDeposit( - targetChainId, - deployedContracts[targetChainId].CrossChainReceiver!, - recipientAddress, - amount, - tokenAddress, - { value: cost } // Attach the necessary fee for cross-chain transfer - ); - await transferTx.wait(); - console.log( - `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` - ); + address registrationOwner; + mapping(uint16 => bytes32) registeredSenders; + + constructor(address _wormholeRelayer, address _wormhole) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + wormhole = IWormhole(_wormhole); + registrationOwner = msg.sender; + } + + modifier onlyWormholeRelayer() { + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } + + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } + + /** + * Sets the registered address for 'sourceChain' to 'sourceAddress' + * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid + * + * Assumes only one sender per chain is valid + * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) + */ + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } } - ``` + ``` + +### Interface for Cross-Chain Messages - This part of the script first approves the token transfer, then initiates the cross-chain transfer using the `CrossChainSender` contract, and finally logs the transaction hash for the user to track. +The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. - 4. Finalize the script: +For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: - ```typescript - console.error(error); - process.exit(1); -}); - ``` + - **`IWormholeRelayer`** – methods for sending cross-chain messages, VAAs, and token transfers + - **`IWormholeReceiver`** – the required implementation for receiving cross-chain messages + - **`quoteEVMDeliveryPrice()`** – how to estimate gas and fees for cross-chain transactions - This section finalizes the script by calling the `main` function and handling any errors that may occur during the token transfer process. +These interfaces reduce the complexity of cross-chain dApp development by abstracting away the details of relayer infrastructure, ensuring that message delivery is handled efficiently. -You can find the full code for the `transfer.ts` file below: +### Advanced Concepts -??? code "transfer.ts" +For developers interested in exploring additional advanced topics, the following sections provide insights into key aspects of the SDK’s functionality. - ```solidity - import { ethers } from 'ethers'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +???- note "Error Handling and Reverts" + The SDK defines several custom errors to help developers handle common issues like incorrect gas fees, invalid senders, and more. For example, `InvalidMsgValue` is thrown when the message value for a relayed message is erroneous. -dotenv.config(); + ```solidity + error InvalidMsgValue(uint256 msgValue, uint256 totalFee); + ``` -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +## Usage -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} +This section covers cross-chain messaging and token transfers and shows how to use the Wormhole Solidity SDK in real-world scenarios. -function loadConfig(): ChainConfig[] { - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +### Send a Cross-Chain Message -function loadDeployedContracts(): DeployedContracts { - const contractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - if ( - !fs.existsSync(contractsPath) || - fs.readFileSync(contractsPath, 'utf8').trim() === '' - ) { - console.error( - 'No contracts found. Please deploy contracts first before transferring tokens.' - ); - process.exit(1); - } - return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); -} +To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: -function selectSourceChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const sourceOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainSender - ); +```solidity +pragma solidity ^0.8.19; - if (sourceOptions.length === 0) { - console.error('No source chains available with CrossChainSender deployed.'); - process.exit(1); - } +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; - console.log('\nSelect the source chain:'); - sourceOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +contract CrossChainSender is Base { + constructor( + address _wormholeRelayer, + address _wormhole + ) Base(_wormholeRelayer, _wormhole) {} - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; - return { - chainId: Number(sourceOptions[selectedIndex][0]), - networkName: sourceOptions[selectedIndex][1].networkName, - }; + function sendMessage( + bytes memory message, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Register sender and send message through WormholeRelayer + setRegisteredSender(targetChain, msg.sender); + onlyWormholeRelayer().sendPayloadToEvm( + targetChain, + address(targetAddress), + message, + 0, + 500_000 + ); + } } +``` -function selectTargetChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const targetOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainReceiver - ); - - if (targetOptions.length === 0) { - console.error( - 'No target chains available with CrossChainReceiver deployed.' - ); - process.exit(1); - } +This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. - console.log('\nSelect the target chain:'); - targetOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +### Send Tokens Across Chains - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; - return { - chainId: Number(targetOptions[selectedIndex][0]), - networkName: targetOptions[selectedIndex][1].networkName, - }; -} +The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. -async function main() { - const chains = loadConfig(); - const deployedContracts = loadDeployedContracts(); +```solidity +pragma solidity ^0.8.19; - // Select the source chain (only show chains with CrossChainSender deployed) - const { chainId: sourceChainId, networkName: sourceNetworkName } = - selectSourceChain(deployedContracts); - const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - // Select the target chain (only show chains with CrossChainReceiver deployed) - const { chainId: targetChainId, networkName: targetNetworkName } = - selectTargetChain(deployedContracts); - const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; +contract CrossChainTokenSender is TokenSender { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenSender(_wormholeRelayer, _wormhole) {} - // Set up providers and wallets - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); + function sendToken( + address token, + uint256 amount, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Send tokens across chains + transferTokenToTarget(token, amount, targetChain, targetAddress); + } +} +``` - // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) - const CrossChainSenderArtifact = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. - const abi = CrossChainSenderArtifact.abi; +### Receive Tokens Across Chains - // Create the contract instance using the full ABI - const CrossChainSender = new ethers.Contract( - deployedContracts[sourceChainId].CrossChainSender!, - abi, - wallet - ); +To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. - // Display the selected chains - console.log( - `\nInitiating transfer from ${sourceNetworkName} to ${targetNetworkName}.` - ); +```solidity +pragma solidity ^0.8.19; - // Ask the user for token transfer details - const tokenAddress = readlineSync.question( - 'Enter the token contract address: ' - ); - const recipientAddress = readlineSync.question( - 'Enter the recipient address on the target chain: ' - ); +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - // Get the token contract - const tokenContractDecimals = new ethers.Contract( - tokenAddress, - [ - 'function decimals() view returns (uint8)', - 'function approve(address spender, uint256 amount) public returns (bool)', - ], - wallet - ); +contract CrossChainTokenReceiver is TokenReceiver { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenReceiver(_wormholeRelayer, _wormhole) {} - // Fetch the token decimals - const decimals = await tokenContractDecimals.decimals(); + // Function to handle received tokens from another chain + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable override { + // Process the received tokens here + receiveTokens(payload); + } +} +``` - // Get the amount from the user, then parse it according to the token's decimals - const amount = ethers.parseUnits( - readlineSync.question('Enter the amount of tokens to transfer: '), - decimals - ); +In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. - // Calculate the cross-chain transfer cost - const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId); +!!! note + Always verify the source of incoming messages and tokens to prevent unauthorized access to your contract. Please refer to the [Emitter Verification](/docs/products/messaging/guides/core-contracts/#validating-the-emitter/){target=\_blank} section for more details. - // Approve the CrossChainSender contract to transfer tokens on behalf of the user - const tokenContract = new ethers.Contract( - tokenAddress, - ['function approve(address spender, uint256 amount) public returns (bool)'], - wallet - ); +## Testing Environment - const approveTx = await tokenContract.approve( - deployedContracts[sourceChainId].CrossChainSender!, - amount - ); - await approveTx.wait(); - console.log(`Approved tokens for cross-chain transfer.`); +The SDK includes built-in support for Forge-based testing, which allows you to test your cross-chain applications locally before deploying them to production. Testing with the same Solidity compiler version and configuration you plan to use in production is highly recommended to catch any potential issues early. - // Initiate the cross-chain transfer - const transferTx = await CrossChainSender.sendCrossChainDeposit( - targetChainId, - deployedContracts[targetChainId].CrossChainReceiver!, - recipientAddress, - amount, - tokenAddress, - { value: cost } // Attach the necessary fee for cross-chain transfer - ); - await transferTx.wait(); - console.log( - `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` - ); -} +For a detailed example, check out the below repositories: -main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` + - [Cross chain messaging](/docs/products/messaging/tutorials/cross-chain-contracts/){target=\_blank} + - [Cross chain token transfer](/docs/products/messaging/tutorials/cross-chain-token-contracts/){target=\_blank} +--- END CONTENT --- -### Transfer Tokens +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/get-started/ +--- BEGIN CONTENT --- -Now that your transfer script is ready, it’s time to execute it and perform a cross-chain token transfer. +--- END CONTENT --- -1. **Run the transfer script** +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ +--- BEGIN CONTENT --- +--- +title: Building Protocols and Payloads +description: Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. +categories: Typescript-SDK +--- - Open your terminal and run the transfer script: +# Building Protocols and Payloads - ```bash - npx ts-node script/transfer.ts - ``` +## Introduction - This command will start the script, prompting you to select the source and target chains, input the token address, recipient address, and the amount of tokens to transfer. +The [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} provides a flexible and powerful system for integrating cross-chain communication into your applications. A key feature of the SDK is its ability to define protocols—modular units representing distinct functionalities—and their associated payloads, which encapsulate the data required for specific operations within those protocols. -2. **Follow the prompts** - the script will guide you through selecting the source and target chains and entering the necessary details for the token transfer. Once you provide all the required information, the script will initiate the token transfer +This guide will help you understand how to build protocols and payloads in the SDK, covering: -3. **Verify the transaction** - after running the script, you should see a confirmation message with the transaction hash. You can use this transaction hash to check the transfer status on the respective blockchain explorers + - The role of protocols and payloads in cross-chain communication + - The mechanics of registering protocols and payloads using the SDK + - Best practices for creating strongly typed layouts to ensure compatibility and reliability + - Real-world examples using the `TokenBridge` as a reference implementation -You can verify the transaction on the [Wormhole Explorer](https://wormholescan.io/){target=\_balnk} using the link provided in the terminal output. This explorer also offers the option to add the transferred token to your MetaMask wallet automatically. +By the end of this guide, you’ll have a solid understanding of how to define, register, and use protocols and payloads in your projects. -If you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this: +## What is a Protocol? -
-npx ts-node transfer.ts - > cross-chain-token-transfer@1.0.0 transfer - > npx ts-node script/transfer.ts - - Select the source chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the SOURCE chain: 1 - - Select the target chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the TARGET chain: 2 - - Initiating transfer from Avalanche testnet fuji to Celo Testnet - Enter the token contract address: 0x5425890298aed601595a70ab815c96711a31bc65 - Enter the recipient address on the target chain: INSERT_YOUR_WALLET_ADDRESS - Enter the amount of tokens to transfer: 2 - Approved tokens for cross-chain transfer. - Transfer initiated from Avalanche testnet fuji to Celo Testnet. Transaction Hash: 0x4a923975d955c1f226a1c2f61a1a0fa1ab1a9e229dc29ceaeadf8ef40acd071f - -
+In the Wormhole SDK, a protocol represents a significant feature or functionality that operates across multiple blockchains. Protocols provide the framework for handling specific types of messages, transactions, or operations consistently and standardized. -!!! note - In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. We sent two units of USDC Testnet tokens using the token contract address `0x5425890298aed601595a70ab815c96711a31bc65`. You can replace these details with those relevant to your project or use the same for testing purposes. +Examples of Protocols: -## Resources + - **`TokenBridge`** - enables cross-chain token transfers, including operations like transferring tokens and relaying payloads + - **`NTT (Native Token Transfers)`** - manages native token movements across chains -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in the [Cross-Chain Token Transfers GitHub repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank}. The repository includes all the scripts, contracts, and configurations needed to deploy and transfer tokens across chains using the Wormhole protocol. +Protocols are defined by: -## Conclusion + - **A `name`** - a string identifier (e.g., `TokenBridge`, `Ntt`) + - **A set of `payloads`** - these represent the specific actions or messages supported by the protocol, such as `Transfer` or `TransferWithPayload` -Congratulations! You've successfully built and deployed a cross-chain token transfer system using Solidity and the Wormhole protocol. You've learned how to: +Each protocol is registered in the Wormhole SDK, allowing developers to leverage its predefined features or extend it with custom payloads. - - Set up a new Solidity project using Foundry - - Develop smart contracts to send and receive tokens across chains - - Write deployment scripts to manage and deploy contracts on different networks ---- END CONTENT --- +## What is a Payload? -Doc-Content: https://wormhole.com/docs/tutorials/solidity-sdk/ ---- BEGIN CONTENT --- ---- -title: Solidity SDK Tutorials -description: Master cross-chain smart contracts with Wormhole's Solidity SDK. Learn messaging, token transfers, and secure, scalable dApp deployments across blockchains. ---- +A payload is a structured piece of data that encapsulates the details of a specific operation within a protocol. It defines the format, fields, and types of data used in a message or transaction. Payloads ensure consistency and type safety when handling complex cross-chain operations. -# Solidity SDK +Each payload is defined as: -Expand the reach of your decentralized applications by building smart contracts that can communicate across multiple blockchains. Through these tutorials, you’ll learn to create robust cross-chain contracts, enabling your dApps to tap into global liquidity, diverse functionalities, and a broader user base. + - **A `layout`** - describes the binary format of the payload fields + - **A `literal`** - combines the protocol name and payload name into a unique identifier (e.g., `TokenBridge:Transfer`) -## Tutorials +By registering payloads, developers can enforce type safety and enable serialization and deserialization for specific protocol operations. -
+## Register Protocols and Payloads -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Messaging Contracts** +Protocols and payloads work together to enable cross-chain communication with precise type safety. For instance, in the `TokenBridge` protocol: - --- + - The protocol is registered under the `TokenBridge` namespace + - Payloads like `Transfer` or `AttestMeta` are linked to the protocol to handle specific operations - Learn how to build and deploy smart contracts that communicate seamlessly across multiple blockchains. This tutorial walks you through using Wormhole's Solidity SDK to send and receive messages between Avalanche Fuji and Celo Alfajores, helping you master emitter validation, relayer usage, and cross-chain cost management. +Understanding the connection between these components is important for customizing or extending the SDK to suit your needs. - [:custom-arrow: Start building](/docs/products/messaging/tutorials/cross-chain-contracts/) +### Register Protocols -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Token Transfer Contracts** +Registering a protocol establishes its connection to Wormhole's infrastructure, ensuring it interacts seamlessly with payloads and platforms while maintaining type safety and consistency. - --- +#### How Protocol Registration Works - Discover how to create a fully functional cross-chain token transfer system using Wormhole's Solidity SDK. This tutorial guides you through token attestation, contract deployment, and secure transfers of ERC-20 tokens between test networks. By the end, you’ll know how to tap into global liquidity and enrich your dApps with seamless multi-chain asset movement. +Protocol registration involves two key tasks: - [:custom-arrow: Start building](/docs/products/messaging/tutorials/cross-chain-token-contracts/) + - **Mapping protocols to interfaces** - connect the protocol to its corresponding interface, defining its expected behavior across networks (`N`) and chains (`C`). This ensures type safety, similar to strong typing, by preventing runtime errors if protocol definitions are incorrect + - **Linking protocols to platforms** - specify platform-specific implementations if needed, or use default mappings for platform-agnostic protocols -
+For example, here's the `TokenBridge` protocol registration: -## Additional Resources +```typescript +declare module '../../registry.js' { + export namespace WormholeRegistry { + interface ProtocolToInterfaceMapping { + TokenBridge: TokenBridge; + } + interface ProtocolToPlatformMapping { + TokenBridge: EmptyPlatformMap<'TokenBridge'>; + } + } +} + +``` -
+This code snippet: -- :octicons-book-16:{ .lg .middle } **Core Contracts** + - Maps the `TokenBridge` protocol to its interface to define how it operates + - Links the protocol to a default platform mapping via `EmptyPlatformMap` - --- +You can view the full implementation in the [`TokenBridge` protocol file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L14-L70){target=\_blank}. - Dive deeper into Wormhole’s foundational concepts for cross-chain contracts. Discover how messaging, guardians, and VAAs work together to enable secure, scalable dApps. +#### Platform-Specific Protocols - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +Some protocols require platform-specific behavior. For instance, the EVM-compatible Wormhole Registry maps native addresses for Ethereum-based chains: -
---- END CONTENT --- +```typescript +declare module '@wormhole-foundation/sdk-connect' { + export namespace WormholeRegistry { + interface PlatformToNativeAddressMapping { + Evm: EvmAddress; + } + } +} -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/ ---- BEGIN CONTENT --- ---- -title: Wormhole SDK Tutorials -description: Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. ---- +registerNative(_platform, EvmAddress); +``` -# Wormhole SDK +This ensures that `EvmAddress` is registered as the native address type for EVM-compatible platforms. See the [EVM platform address file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/platforms/evm/src/address.ts#L98-L106){target=\_blank} for details. -The Wormhole SDK provides the essential building blocks for creating robust cross-chain applications. With its developer-friendly libraries, tools, and interfaces, you can quickly integrate Wormhole’s messaging, token transfer, and governance functionalities into your projects. Whether you’re building a simple cross-chain dApp or architecting a complex multi-chain ecosystem, these tutorials will guide you through mastering the SDK and unlocking the full potential of Wormhole’s infrastructure. +### Register Payloads -## Tutorials +[Payload registration](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts){target=\_blank} enables developers to define, serialize, and handle custom message types within their protocols. It establishes the connection between a protocol and its payloads, ensuring seamless integration, type enforcement, and runtime efficiency. -
+This process ties a protocol to its payloads using a combination of: -- :octicons-repo-16:{ .lg .middle } **Transfer USDC via CCTP** + - **Payload literals** - unique identifiers in the format `:`. These literals map each payload to a layout + - **Payload layouts** - structures that define the binary representation of payload data + - **The payload factory** - a centralized runtime registry that maps payload literals to layouts for dynamic resolution and serialization - --- +These components work together to streamline the definition and management of protocol payloads. - Learn how to move native USDC across chains using Circle’s CCTP and Wormhole’s TypeScript SDK. This tutorial shows you how to streamline transfers with automated attestation and finalization or take complete control with manual steps. Gain the skills to handle seamless USDC bridging, optimize user experience, and improve the reliability of your cross-chain applications. +#### How Payload Registration Works - [:custom-arrow: Start building](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/) +Payload registration involves: -- :octicons-repo-16:{ .lg .middle } **Transfer Tokens via the Token Bridge** +1. **Define payload layouts** - create layouts to structure your payloads. For instance, a protocol might use a `TransferWithPayload` layout: - --- + ```typescript + export const transferWithPayloadLayout = < + const P extends CustomizableBytes = undefined +>( + customPayload?: P +) => + [ + payloadIdItem(3), + ...transferCommonLayout, + { name: 'from', ...universalAddressItem }, + customizableBytes({ name: 'payload' }, customPayload), + ] as const; + ``` - Learn how to build a versatile cross-chain token transfer application using Wormhole’s TypeScript SDK. This tutorial walks you through leveraging the Token Bridge to securely and efficiently move assets between EVM and non-EVM chains. By the end, you’ll understand how to transfer tokens between networks like Ethereum, Solana, Sui, and beyond, opening the door to an interconnected blockchain ecosystem. +2. **Register payloads** - use `registerPayloadTypes` to map payload literals to their layouts: - [:custom-arrow: Start building](/docs/products/token-bridge/tutorials/transfer-workflow/) + ```typescript + registerPayloadTypes('ProtocolName', protocolNamedPayloads); + ``` -
+3. **Access registered payloads** - use the [`getPayloadLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/9105de290c91babbf8ad031bd89cc75ee38739c8/core/definitions/src/vaa/functions.ts#L19-L23){target=\_blank} function to fetch the layout for a specific payload literal. This method ensures that the correct layout is retrieved dynamically and safely: -## Additional Resources + ```typescript + const layout = getPayloadLayout('ProtocolName:PayloadName'); + ``` -
+These steps link payload literals and their layouts, enabling seamless runtime handling. -- :octicons-tools-16:{ .lg .middle } **Wormhole SDK Documentation** +#### The Payload Factory - --- +At the core of the payload registration process is the `payloadFactory`, a registry that manages the mapping between payload literals and layouts: - Learn to build cross-chain dApps using the Wormhole SDK. Access detailed guides, reference code, and best practices for robust application development. +```typescript +export const payloadFactory = new Map(); - [:custom-arrow: Learn more](/docs/tools/typescript-sdk/get-started/) +export function registerPayloadType( + protocol: ProtocolName, + name: string, + layout: Layout +) { + const payloadLiteral = composeLiteral(protocol, name); + if (payloadFactory.has(payloadLiteral)) { + throw new Error(`Payload type ${payloadLiteral} already registered`); + } + payloadFactory.set(payloadLiteral, layout); +} + +``` -
---- END CONTENT --- + - The `payloadFactory` ensures each payload literal maps to its layout uniquely + - The [`registerPayloadType`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts#L46-L52){target=\_blank} function adds individual payloads, while [`registerPayloadTypes`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/vaa/registration.ts#L62-L64){target=\_blank} supports bulk registration -Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/transfer-workflow/ ---- BEGIN CONTENT --- ---- -title: Transfer Tokens via Token Bridge Tutorial -description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains ---- +This implementation ensures dynamic, efficient handling of payloads at runtime. -# Transfer Tokens via the Token Bridge +## Integrate Protocols with Payloads -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} +Integrating payloads with protocols enables dynamic identification through payload literals, while serialization and deserialization ensure their binary representation is compatible across chains. For more details on these processes, refer to the [Layouts page](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}. -## Introduction +### Payload Discriminators -This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. +Payload discriminators are mechanisms in the Wormhole SDK that dynamically identify and map incoming payloads to their respective layouts at runtime. They are relevant for protocols like `TokenBridge`, enabling efficient handling of diverse payload types while ensuring type safety and consistent integration. -By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: +#### How Discriminators Work - - EVM to EVM (e.g., Ethereum to Avalanche) - - EVM to non-EVM chains (e.g., Ethereum to Solana) - - Non-EVM to EVM chains (e.g., Sui to Avalanche) - - Non-EVM to non-EVM chains (e.g., Solana to Sui) +Discriminators evaluate serialized binary data and determine the corresponding payload layout by inspecting fixed fields or patterns within the data. Each payload layout is associated with a payload literal (e.g., `TokenBridge:Transfer` or `TokenBridge:TransferWithPayload`). -Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. +This system ensures: -At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. + - **Dynamic runtime identification** - payloads are parsed based on their content, even if a single protocol handles multiple payload types + - **Strict type enforcement** - discriminators leverage layout mappings to prevent invalid payloads from being processed -## Prerequisites +Below is an example of how the Wormhole SDK builds a discriminator to distinguish between payload layouts: -Before you begin, ensure you have the following: +```typescript +export function layoutDiscriminator( + layouts: readonly Layout[], + allowAmbiguous?: B +): Discriminator { + // Internal logic to determine distinguishable layouts + const [distinguishable, discriminator] = internalBuildDiscriminator(layouts); + if (!distinguishable && !allowAmbiguous) { + throw new Error('Cannot uniquely distinguish the given layouts'); + } - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - Native tokens (testnet or mainnet) in Solana and Sui wallets - - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees + return ( + !allowAmbiguous + ? (encoded: BytesType) => { + const layout = discriminator(encoded); + return layout.length === 0 ? null : layout[0]; + } + : discriminator + ) as Discriminator; +} + +``` -## Supported Chains + - [`layoutDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/9105de290c91babbf8ad031bd89cc75ee38739c8/core/base/src/utils/layout.ts#L16){target=\_blank} takes a list of layouts and generates a function that can identify the appropriate layout for a given serialized payload + - The `allowAmbiguous` parameter determines whether layouts with overlapping characteristics are permitted -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. +### Real-World Example: Token Bridge Protocol -## Project Setup +Integrating protocols with their respective payloads exemplifies how the Wormhole SDK leverages layouts and type-safe registration mechanisms to ensure efficient cross-chain communication. This section focuses on how protocols like `TokenBridge` use payloads to facilitate specific operations. -In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. +#### Token Bridge Protocol and Payloads -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project +The `TokenBridge` protocol enables cross-chain token transfers through its payloads. Key payloads include: - ```bash - mkdir native-transfers - cd native-transfers - npm init -y - ``` + - **`Transfer`** - handles basic token transfer operations + - **`TransferWithPayload`** - extends the `Transfer` payload to include custom data, enhancing functionality -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +Payloads are registered to the `TokenBridge` protocol via the `PayloadLiteralToLayoutMapping` interface, which links payload literals (e.g., `TokenBridge:Transfer`) to their layouts. - ```bash - npm install @wormhole-foundation/sdk dotenv tsx - ``` +Additionally, the protocol uses reusable layouts like [`transferCommonLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L29C7-L47){target=\_blank} and extends them in more specialized layouts such as [`transferWithPayloadLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/76b20317b0f68e823d4e6c4a2e41bb2a7705c64f/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts#L49-L57){target=\_blank}: -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +```typescript +export const transferWithPayloadLayout = < + const P extends CustomizableBytes = undefined +>( + customPayload?: P +) => + [ + payloadIdItem(3), + ...transferCommonLayout, + { name: 'from', ...universalAddressItem }, + customizableBytes({ name: 'payload' }, customPayload), + ] as const; +``` - ```bash - touch .env - ``` +This layout includes: - Inside the `.env` file, add your private keys. + - A `payloadIdItem` to identify the payload type + - Common fields for token and recipient details + - A customizable `payload` field for additional data - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" - ``` +#### Use the Discriminator - !!! note - Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. +To manage multiple payloads, the `TokenBridge` protocol utilizes a discriminator to distinguish between payload types dynamically. For example: -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays +```typescript +const tokenBridgePayloads = ['Transfer', 'TransferWithPayload'] as const; - 1. Create the helpers file +export const getTransferDiscriminator = lazyInstantiate(() => + payloadDiscriminator([_protocol, tokenBridgePayloads]) +); +``` - ```bash - mkdir -p src/helpers - touch src/helpers/helpers.ts - ``` + - The [`getTransferDiscriminator`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dbbbc7c365db602dd3b534f6d615ac80c3d2aaf1/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L67-L70){target=\_blank} function dynamically evaluates payloads using predefined layouts + - This ensures that each payload type is processed according to its unique structure and type-safe layout - 2. Open the `helpers.ts` file and add the following code +#### Register Payloads to Protocols - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, - TokenId, - isTokenId, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import { config } from 'dotenv'; -config(); +Here’s how the `TokenBridge` protocol connects its payloads to the Wormhole SDK: -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; +```typescript +declare module '../../registry.js' { + export namespace WormholeRegistry { + interface PayloadLiteralToLayoutMapping + extends RegisterPayloadTypes< + 'TokenBridge', + typeof tokenBridgeNamedPayloads + > {} + } } -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} +registerPayloadTypes('TokenBridge', tokenBridgeNamedPayloads); +``` -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext, - gasLimit?: bigint -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; +This registration links the `TokenBridge` payload literals to their respective layouts, enabling serialization and deserialization at runtime. - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - const evmSignerOptions = gasLimit ? { gasLimit } : {}; - signer = await ( - await evm() - ).getSigner( - await chain.getRpc(), - getEnv('ETH_PRIVATE_KEY'), - evmSignerOptions - ); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); - break; - case 'Aptos': - signer = await ( - await aptos() - ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); - } +You can explore the complete `TokenBridge` protocol and payload definitions in the [`TokenBridge` layout file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts){target=\_blank}. - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} +#### Token Bridge Payloads -export async function getTokenDecimals< - N extends 'Mainnet' | 'Testnet' | 'Devnet' ->( - wh: Wormhole, - token: TokenId, - sendChain: ChainContext -): Promise { - return isTokenId(token) - ? Number(await wh.getDecimals(token.chain, token.address)) - : sendChain.config.nativeTokenDecimals; -} - - ``` +The following payloads are registered for the `TokenBridge` protocol: - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file - - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers + - **`AttestMeta`** - used for token metadata attestation + - **`Transfer`** - facilitates token transfers + - **`TransferWithPayload`** - adds a custom payload to token transfers -## Check and Create Wrapped Tokens +These payloads and their layouts are defined in the [`TokenBridge` layout file](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridgeLayout.ts){target=\_blank}. -Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. +### Other Protocols: Native Token Transfers (NTT) -In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. +While this guide focuses on the `TokenBridge` protocol, other protocols, like NTT, follow a similar structure. -### Configure the Wrapped Token Script + - NTT manages the transfer of native tokens across chains + - Payloads such as `WormholeTransfer` and `WormholeTransferStandardRelayer` are registered to the protocol using the same patterns for payload literals and layouts + - The same mechanisms for type-safe registration and payload discriminators apply, ensuring reliability and extensibility -1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory +For more details, you can explore the [NTT implementation in the SDK](https://github.com/wormhole-foundation/example-native-token-transfers/blob/00f83aa215338b1b8fd66f522bd0f45be3e98a5a/sdk/definitions/src/ntt.ts){target=\_blank}. +--- END CONTENT --- - ```bash - mkdir -p src/scripts - touch src/scripts/create-wrapped.ts - ``` +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/sdk-layout/ +--- BEGIN CONTENT --- +--- +title: Data Layouts +description: Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. +categories: Typescript-SDK +--- -2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions +# Data Layouts - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; - ``` +## Introduction -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support +The [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} uses the [layout package](https://www.npmjs.com/package/binary-layout){target=\_blank} to define, serialize, and deserialize data structures efficiently. This modular system ensures consistent data formatting and cross-environment compatibility, benefiting projects that require robust handling of structured data. - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` +By understanding the layout mechanism, you’ll be able to: - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. + - Define data structures (numbers, arrays, and custom types) + - Efficiently serialize and deserialize data using the SDK’s utilities + - Handle protocol-specific layouts with ease + +This guide is beneficial for developers looking to integrate Wormhole into their applications or protocols, especially those dealing with complex payloads or cross-chain communication. + +## Key Concepts -4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) +### Layout Items - ```typescript - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); - ``` +A layout defines how data structures should be serialized (converted into binary format) and deserialized (converted back into their original structure). This ensures consistent data formatting when transmitting information across different blockchain environments. -5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation +Layouts are composed of [layout items](https://github.com/nonergodic/layout/blob/main/src/items.ts){target=\_blank}, which describe individual fields or sets of fields in your data. Each layout item specifies: - ```typescript - - ``` + - **`name`** - name of the field + - **`binary`** - type of data (e.g., `uint`, `bytes`) + - **`size`** - byte length for fixed-size fields within uint and bytes items only -6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation +Layout items can represent: - ```typescript - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } - ``` + - **Primitive types** - basic data types like unsigned integers (`uint`) or byte arrays (`bytes`) + - **Composite types** - more complex structures, such as arrays or nested objects - If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. +Below is an example of a layout that might be used to serialize a message across the Wormhole protocol: -7. **Set up the source chain signer** - the signer creates and submits the attestation transaction +```typescript +const exampleLayout = [ + { name: 'sourceChain', binary: 'uint', size: 2 }, + { name: 'orderSender', binary: 'bytes', size: 32 }, + { name: 'redeemer', binary: 'bytes', size: 32 }, + { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 }, +] as const; +``` - ```typescript - - ``` +In this example: -8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step + - `sourceChain` is a 2-byte unsigned integer (`uint`) identifying the source blockchain + - `orderSender` is a fixed-length 32-byte array representing the sender's address + - `redeemer` is another 32-byte array used for the redeemer’s address + - `redeemerMessage` is a variable-length byte sequence, with its length specified by a 4-byte integer - ```typescript - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); +This layout definition ensures that all necessary data fields are consistently encoded and can be correctly interpreted when they are deserialized. - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); - ``` +### Serialization and Deserialization -9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure +Serialization converts structured data into binary format; deserialization reverses this, reconstructing the original objects. - ```typescript - console.log('Parsed Messages:', msgs); +You can serialize data using the `serializeLayout` function: - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } - ``` +```typescript +const serialized = serializeLayout(fillLayout, exampleFill); +``` -10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation +To deserialize the binary data back into a structured object, use the `deserializeLayout` function: - ```typescript - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); +```typescript +const deserialized = deserializeLayout(fillLayout, serialized); +``` - const tsx = await signSendWait(destChain, subAttestation, destSigner); - ``` +### Custom Conversions -11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain +Layouts also allow for custom conversions, which help map complex or custom types (like chain IDs or universal addresses) into a more usable format. This is useful when serializing or deserializing data that doesn’t fit neatly into simple types like integers or byte arrays. - ```typescript - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } +For example, consider a custom conversion for a chain ID: - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` +```typescript +const chainCustomConversion = { + to: (chainId: number) => toChain(chainId), + from: (chain: Chain) => chainToChainId(chain), +} satisfies CustomConversion; + +``` - If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. +This setup allows Wormhole to convert between human-readable formats and binary-encoded data used in payloads. -??? code "Complete script" - ```typescript - import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; +### Error Handling -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); +The layout system performs error checks during serialization and deserialization. An error is thrown if data is incorrectly sized or in the wrong format. Refer to the below example: - // Define the source and destination chains - const srcChain = wh.getChain('ArbitrumSepolia'); - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); +```typescript +try { + deserializeLayout(fillLayout, corruptedData); +} catch (error) { + console.error('Error during deserialization:', error.message); +} +``` - // Destination chain signer setup - const { signer: destSigner } = await getSigner(destChain, gasLimit); - const tbDest = await destChain.getTokenBridge(); +## Application of Layouts - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } +This section will focus on applying the concepts explained earlier through examples. These will help developers better understand how to define layouts, serialize and deserialize data, and use custom conversions where needed. - // Source chain signer setup - const { signer: origSigner } = await getSigner(srcChain); +### Defining Layouts - // Create an attestation transaction on the source chain - const tbOrig = await srcChain.getTokenBridge(); - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); +To get started with layouts in Wormhole, you need to define your structure. A layout is simply a list of fields (layout items) describing how each data piece will be serialized. - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); +Consider the following layout for a payload: - // Retrieve the Wormhole message ID from the attestation transaction - const msgs = await srcChain.parseTransaction(txid); - console.log('Parsed Messages:', msgs); +```typescript +const exampleLayout = [ + { name: 'sourceChain', binary: 'uint', size: 2 }, + { name: 'orderSender', binary: 'bytes', size: 32 }, + { name: 'redeemer', binary: 'bytes', size: 32 }, + { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 }, +] as const; +``` - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } +In this example: - console.log('Token Address: ', vaa.payload.token.address); + - `sourceChain` is an unsigned integer (uint) of 2 bytes + - `orderSender` is a 32-byte fixed-length byte array + - `redeemer` is another 32-byte byte array + - `redeemerMessage` is a length-prefixed byte array, with the length specified by a 4-byte integer - // Submit the attestation on the destination chain - console.log('Attesting asset on destination chain...'); +### Serialize Data - const subAttestation = tbDest.submitAttestation( - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); +Once a layout is defined, the next step is to serialize data according to that structure. You can accomplish this using the `serializeLayout` function from the Wormhole SDK. - const tsx = await signSendWait(destChain, subAttestation, destSigner); - console.log('Transaction hash: ', tsx); +```typescript +const examplePayload = { + sourceChain: 6, + orderSender: new Uint8Array(32), + redeemer: new Uint8Array(32), + redeemerMessage: new Uint8Array([0x01, 0x02, 0x03]), +}; - // Poll for the wrapped asset until it's available - async function waitForIt() { - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } +const serializedData = serializeLayout(exampleLayout, examplePayload); +``` - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` +This takes the data structure (`examplePayload`) and serializes it according to the rules defined in the layout (`exampleLayout`). The result is a `Uint8Array` representing the serialized binary data. -### Run the Wrapped Token Creation +### Deserialize Data -Once the script is ready, execute it with: +Deserialization is the reverse of serialization. Given a serialized `Uint8Array`, we can convert it back into its original structure using the `deserializeLayout` function. -```bash -npx tsx src/scripts/create-wrapped.ts +```typescript +const deserializedPayload = deserializeLayout(exampleLayout, serializedData); ``` -If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. +This will output the structured object, making it easy to work with data transmitted or received from another chain. -## Token Transfers +### Handling Variable-Length Fields + +One relevant aspect of Wormhole SDK's layout system is the ability to handle variable-length fields, such as arrays and length-prefixed byte sequences. + +For instance, if you want to serialize or deserialize a message where the length of the content isn't known beforehand, you can define a layout item with a `lengthSize` field. + +```typescript +{ name: 'message', binary: 'bytes', lengthSize: 4 } +``` -In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. +This tells the SDK to read or write the message's length (in 4 bytes) and then handle the content. -### Configure Transfer Details +## Nested Layouts and Strong Typing -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. +The Wormhole SDK simplifies handling complex structures with nested layouts and strong typing. Nested layouts clearly represent hierarchical data, while strong typing ensures data consistency and catches errors during development. -1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains +### Nested Layout - ```bash - touch src/scripts/native-transfer.ts - ``` +In complex protocols, layouts can contain nested structures. Nested layouts become relevant here, allowing you to represent hierarchical data (such as transactions or multi-part messages) in a structured format. -2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files +Refer to the following nested layout where a message contains nested fields: - ```typescript - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - ``` +```typescript +const nestedLayout = [ + { + name: 'source', + binary: 'bytes', + layout: [ + { name: 'chainId', binary: 'uint', size: 2 }, + { name: 'sender', binary: 'bytes', size: 32 }, + ], + }, + { + name: 'redeemer', + binary: 'bytes', + layout: [ + { name: 'address', binary: 'bytes', size: 32 }, + { name: 'message', binary: 'bytes', lengthSize: 4 }, + ], + }, +] as const satisfies Layout; +``` -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support +In this layout: - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` + - `source` is an object with two fields: `chainId` and `sender` + - `redeemer` is another object with two fields: `address` and a length-prefixed `message` -4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them +### Strong Typing - ```typescript - const rcvChain = wh.getChain('Solana'); - ``` +One of the benefits of using the Wormhole SDK in TypeScript is its support for strong typing. This ensures that serialized and deserialized data conform to expected structures, reducing errors during development by enforcing type checks at compile time. -5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains +Using TypeScript, the `LayoutToType` utility provided by the SDK automatically generates a strongly typed structure based on the layout: - ```typescript - const destination = await getSigner(rcvChain); - ``` +```typescript +type NestedMessage = LayoutToType; +``` -6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object +This ensures that when you serialize or deserialize data, it matches the expected structure. - ```typescript - - ``` +```typescript +const message: NestedMessage = { + source: { + chainId: 6, + sender: new Uint8Array(32), + }, + redeemer: { + address: new Uint8Array(32), + message: new Uint8Array([0x01, 0x02, 0x03]), + }, +}; +``` -7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit +Attempting to assign data of incorrect types will result in a compile-time error. The Wormhole SDK's layout system enforces strong types, reducing runtime errors and improving code reliability. - ```typescript - - ``` +### Serialization and Deserialization with Nested Layouts -8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself +You can serialize and deserialize nested structures in the same way as simpler layouts: - ```typescript - - ``` +```typescript +const serializedNested = serializeLayout(nestedLayout, message); +const deserializedNested = deserializeLayout(nestedLayout, serializedNested); +``` - !!! note - Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. - -9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function +Strong typing in TypeScript ensures that the message object conforms to the nested layout structure. This reduces the risk of data inconsistency during cross-chain communication. - ```typescript - - ``` +## Commonly Used Layouts -10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` +The Wormhole SDK includes predefined layouts frequently used in cross-chain messaging. These layouts are optimized for standard fields such as chain IDs, addresses, and signatures. You can explore the complete set of predefined layouts in the [`layout-items` directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/layout-items){target=\_blank} of the Wormhole SDK. - ```typescript - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); - ``` +### Chain ID Layouts - Finally, we use `process.exit(0);` to close the script once the transfer completes +Chain ID layouts in the Wormhole SDK derive from a common foundation: `chainItemBase`. This structure defines the binary representation of a chain ID as a 2-byte unsigned integer, ensuring consistency across serialization and deserialization processes. - ```typescript - })(); - ``` +#### Base Structure -### Token Transfer Logic +This simple structure is the blueprint for more specific layouts by standardizing the binary format and size. -This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. +```typescript +const chainItemBase = { binary: 'uint', size: 2 } as const; +``` -#### Defining the Token Transfer Function +#### Dynamic Chain ID Layout -The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. +The dynamic chain ID layout, [`chainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L13-L40){target=\_blank}, extends `chainItemBase` by adding flexible custom conversion logic. It enables runtime validation of chain IDs, supports optional null values, and restricts chain IDs to a predefined set when needed. ```typescript -wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic -import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; +export const chainItem = < + const C extends readonly Chain[] = typeof chains, + const N extends boolean = false, +>(opts?: { + allowedChains?: C; + allowNull?: N; +}) => + ({ + ...chainItemBase, // Builds on the base structure + custom: { + to: (val: number): AllowNull => { ... }, + from: (val: AllowNull): number => { ... }, + }, + }); +``` -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); +This layout is versatile. It allows the serialization of human-readable chain names (e.g., `Ethereum`) to numeric IDs (e.g., `1`) and vice versa. This is particularly useful when working with dynamic configurations or protocols supporting multiple chains. - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); +#### Fixed Chain ID Layout - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +The fixed chain ID layout, [`fixedChainItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/chain.ts#L42-L49){target=\_blank}, is more rigid. It also extends `chainItemBase`, but the custom field is hardcoded for a single chain. This eliminates runtime validation and enforces strict adherence to a specific chain. - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); +```typescript +export const fixedChainItem = (chain: C) => ({ + ...chainItemBase, // Builds on the base structure + custom: { + to: chain, + from: chainToChainId(chain), + }, +}); + +``` - // Define the amount of tokens to transfer - const amt = '1'; +This layout allows developers to efficiently serialize and deserialize messages involving a single, fixed chain ID. - // Set automatic transfer to false for manual transfer - const automatic = false; +### Address Layout - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); +The Wormhole SDK uses a Universal Address Layout to serialize and deserialize blockchain addresses into a standardized format. This layout ensures that addresses are always represented as fixed 32-byte binary values, enabling seamless cross-chain communication. - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); +#### Base Structure - process.exit(0); -})(); +The [`universalAddressItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/universalAddress.ts#L7-L14){target=\_blank} defines the layout for addresses. It uses the binary type bytes and enforces a fixed size of 32 bytes for consistency. -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); +```typescript +export const universalAddressItem = { + binary: 'bytes', + size: 32, + custom: { + to: (val: Uint8Array): UniversalAddress => new UniversalAddress(val), + from: (val: UniversalAddress): Uint8Array => val.toUint8Array(), + } satisfies CustomConversion, +} as const satisfies LayoutItem; + +``` + +This layout ensures consistent address handling by defining the following: + + - **Serialization** - converts a high-level `UniversalAddress` object into raw binary (32 bytes) for efficient storage or transmission + - **Deserialization** - converts raw binary back into a `UniversalAddress` object, enabling further interaction in a human-readable or programmatic format - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +### Signature Layout - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +In the Wormhole SDK, the Signature Layout defines how to serialize and deserialize cryptographic signatures. These signatures verify message authenticity and ensure data integrity, particularly in Guardian-signed VAAs. - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); +#### Base Structure - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); +The `signatureLayout` specifies the binary structure of a secp256k1 signature. It divides the signature into three components: - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - +```typescript +const signatureLayout = [ + { name: 'r', binary: 'uint', size: 32 }, + { name: 's', binary: 'uint', size: 32 }, + { name: 'v', binary: 'uint', size: 1 }, +] as const satisfies Layout; ``` -#### Steps to Transfer Tokens +This layout provides a clear binary format for the secp256k1 signature, making it efficient to process within the Wormhole protocol. -The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: +#### Layout with Custom Conversion -1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step +The [`signatureItem`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/layout-items/signature.ts#L15-L22){target=\_blank} builds upon the `signatureLayout` by adding custom conversion logic. This conversion transforms raw binary data into a high-level `Signature` object and vice versa. - ```typescript - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); - ``` +```typescript +export const signatureItem = { + binary: 'bytes', + layout: signatureLayout, + custom: { + to: (val: LayoutToType) => + new Signature(val.r, val.s, val.v), + from: (val: Signature) => ({ r: val.r, s: val.s, v: val.v }), + } satisfies CustomConversion, Signature>, +} as const satisfies BytesLayoutItem; + +``` -2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying +The `custom` field ensures seamless integration of raw binary data with the `Signature` class, encapsulating signature-specific logic. - ```typescript - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +## Advanced Use Cases - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; - ``` +The Wormhole SDK’s layout system is designed to handle various data structures and serialization needs. This section will explore more advanced use cases, such as handling conditional data structures, fixed conversions, and optimizing serialization performance. -3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process +???- code "Switch Statements for Conditional Layouts" + + In some cases, the structure of serialized data might change based on a specific field, such as a payload ID. The switch layout type conditionally defines layouts based on a value. + + For example, different message types can be identified using a payload ID, and the layout for each message can be determined at runtime: ```typescript - console.log(`Source Trasaction ID: ${srcTxids[0]}`); + const switchLayout = { + binary: 'switch', + idSize: 1, // size of the payload ID + idTag: 'messageType', // tag to identify the type of message + layouts: [ + [[1, 'messageType1'], fillLayout], // layout for type 1 + [[2, 'messageType2'], fastFillLayout], // layout for type 2 + ], +} as const satisfies Layout; ``` - - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} + The switch statement helps developers parse multiple payload types using the same structure, depending on a control field like an ID. - ???- note "How Cross-Chain Transfers Work in the Background" - When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: +???- code "Fixed Conversions and Omitted Fields" - - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount - - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains - - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network - - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer + Fixed conversions and omitted fields allow developers to handle known, static data without including it in every serialization or deserialization operation. For instance, when specific fields in a layout always hold a constant value, they can be omitted from the deserialized object. - This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. + **Example: Fixed Conversion** -4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain + In some cases, a field may always contain a predefined value. The layout system supports fixed conversions, allowing developers to “hard-code” these values: ```typescript - + const fixedConversionLayout = { + binary: 'uint', + size: 2, + custom: { + to: 'Ethereum', + from: chainToChainId('Ethereum'), + }, +} as const satisfies Layout; ``` -5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer + **Example: Omitted Fields** - ```typescript - console.log(`Completed Transfer: `, destTxids); - ``` + Omitted fields are useful for handling padding or reserved fields that do not carry meaningful information and can safely be excluded from the deserialized output: -??? code "Complete script" ```typescript - import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); - - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); + const omittedFieldLayout = [ + { name: 'reserved', binary: 'uint', size: 2, omit: true }, +] as const satisfies Layout; + ``` - // Define the amount of tokens to transfer - const amt = '1'; + In this example, `reserved` is a padding field with a fixed, non-dynamic value that serves no functional purpose. It is omitted from the deserialized result but still considered during serialization to maintain the correct binary format. - // Set automatic transfer to false for manual transfer - const automatic = false; + Only fields with a fixed, known value, such as padding or reserved fields, should be marked as `omit: true`. Fields with meaningful or dynamic information, such as `sourceChain` or `version`, must remain in the deserialized structure to ensure data integrity and allow seamless round-trip conversions between serialized and deserialized representations. - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); +## Integration with Wormhole Protocol - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); +The layout system facilitates seamless interaction with the Wormhole protocol, mainly when dealing with VAAs. These cross-chain messages must be serialized and deserialized to ensure they can be transmitted and processed accurately across different chains. - process.exit(0); -})(); +### VAAs and Layouts -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); +VAAs are the backbone of Wormhole’s cross-chain communication. Each VAA is a signed message encapsulating important information such as the originating chain, the emitter address, a sequence number, and Guardian signatures. The Wormhole SDK leverages its layout system to define, serialize, and deserialize VAAs, ensuring data integrity and chain compatibility. - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +#### Base VAA Structure - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +The Wormhole SDK organizes the VAA structure into three key components: - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); + - [**Header**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L37-L41){target=\_blank} - contains metadata such as the Guardian set index and an array of Guardian signatures + - [**Envelope**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} - includes chain-specific details such as the emitter chain, address, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} + - **Payload** - provides application-specific data, such as the actual message or operation being performed - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); +**Header layout:** - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - - ``` +```typescript +const guardianSignatureLayout = [ + { name: 'guardianIndex', binary: 'uint', size: 1 }, + { name: 'signature', ...signatureItem }, +] as const satisfies Layout; -### Run the Native Token Transfer +export const headerLayout = [ + { name: 'version', binary: 'uint', size: 1, custom: 1, omit: true }, + { name: 'guardianSet', ...guardianSetItem }, + { + name: 'signatures', + binary: 'array', + lengthSize: 1, + layout: guardianSignatureLayout, + }, +] as const satisfies Layout; +``` -Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: +The header defines metadata for validating and processing the VAA, such as the Guardian set index and signatures. Each signature is represented using the `signatureItem` layout, ensuring consistency and compatibility across different platforms. -```bash -npx tsx src/scripts/native-transfer.ts -``` +!!! note "Signature Standard Compliance" -This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). + The signature field uses the `signatureItem` layout, which is explicitly defined as 65 bytes. This layout is aligned with widely used standards such as EIP-2612 and Uniswap's Permit2, ensuring compatibility with cryptographic protocols and applications. -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +**Envelope layout:** -## Resources +```typescript +export const envelopeLayout = [ + { name: 'timestamp', binary: 'uint', size: 4 }, + { name: 'nonce', binary: 'uint', size: 4 }, + { name: 'emitterChain', ...chainItem() }, + { name: 'emitterAddress', ...universalAddressItem }, + { name: 'sequence', ...sequenceItem }, + { name: 'consistencyLevel', binary: 'uint', size: 1 }, +] as const satisfies Layout; +``` -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. +The envelope encapsulates the VAA's core message data, including chain-specific information like the emitter address and sequence number. This structured layout ensures that the VAA can be securely transmitted across chains. -## Conclusion +**Payload Layout:** -You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. +The Payload contains the user-defined data specific to the application or protocol, such as a token transfer message, governance action, or other cross-chain operation. The layout of the payload is dynamic and depends on the payload type, identified by the `payloadLiteral` field. -The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. ---- END CONTENT --- +```typescript +const examplePayloadLayout = [ + { name: 'type', binary: 'uint', size: 1 }, + { name: 'data', binary: 'bytes', lengthSize: 2 }, +] as const satisfies Layout; +``` -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ ---- BEGIN CONTENT --- ---- -title: Transfer USDC via CCTP and Wormhole SDK -description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. ---- +This example demonstrates a payload containing: -# Transfer USDC via CCTP and Wormhole SDK + - A type field specifying the operation type (e.g., transfer or governance action) + - A data field that is length-prefixed and can store operation-specific information -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} +Dynamic payload layouts are selected at runtime using the `payloadLiteral` field, which maps to a predefined layout in the Wormhole SDK. -## Introduction +**Combined Base Layout:** -In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. +The base VAA layout combines the header, envelope, and dynamically selected payload layout: -Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. +```typescript +export const baseLayout = [...headerLayout, ...envelopeLayout] as const; +``` -Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. +At runtime, the payload layout is appended to the `baseLayout` to form the complete structure. -In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. +#### Serializing VAA Data -## Core Concepts +The Wormhole SDK provides the [`serialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L48-L54){target=\_blank} function to serialize a VAA message. This function combines the base layout (header and envelope) with the appropriate payload layout, ensuring the message’s format is correct for transmission across chains. -When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: +```typescript +import { serialize } from '@wormhole-foundation/sdk-core/vaa/functions'; - - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain +const vaaData = { + guardianSet: 1, + signatures: [{ guardianIndex: 0, signature: new Uint8Array(65).fill(0) }], + timestamp: 1633000000, + nonce: 42, + emitterChain: 2, // Ethereum + emitterAddress: new Uint8Array(32).fill(0), + sequence: BigInt(1), + consistencyLevel: 1, + payloadLiteral: 'SomePayloadType', + payload: { key: 'value' }, +}; - - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you +const serializedVAA = serialize(vaaData); +``` -## Prerequisites +???- note "How does it work?" -Before you begin, ensure you have the following: + Internally, the serialize function dynamically combines the `baseLayout` (header and envelope) with the payload layout defined by the `payloadLiteral`. The complete layout is then passed to the `serializeLayout` function, which converts the data into binary format. - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples - - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees + ```typescript + const layout = [ + ...baseLayout, // Header and envelope layout + payloadLiteralToPayloadItemLayout(vaa.payloadLiteral), // Payload layout +] as const; -## Supported Chains +return serializeLayout(layout, vaa as LayoutToType); + + ``` -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. +#### Deserializing VAA Data -## Project Setup +The Wormhole SDK provides the [`deserialize`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/vaa/functions.ts#L162-L200){target=\_blank} function to parse a VAA from its binary format back into a structured object. This function uses the `baseLayout` and payload discriminator logic to ensure the VAA is correctly interpreted. -In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. +```typescript +import { deserialize } from '@wormhole-foundation/sdk-core/vaa/functions'; -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project +const serializedVAA = new Uint8Array([ + /* Serialized VAA binary data */ +]); - ```bash - mkdir cctp-circle - cd cctp-circle - npm init -y - ``` +const vaaPayloadType = 'SomePayloadType'; // The payload type expected for this VAA +const deserializedVAA = deserialize(vaaPayloadType, serializedVAA); +``` -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +???- note "How does it work?" - ```bash - npm install @wormhole-foundation/sdk dotenv - ``` + Internally, the `deserialize` function uses the `baseLayout` (header and envelope) to parse the main VAA structure. It then identifies the appropriate payload layout using the provided payload type or discriminator. -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project + ```typescript + const [header, envelopeOffset] = deserializeLayout(headerLayout, data, { + consumeAll: false, +}); - ```bash - touch .env - ``` +const [envelope, payloadOffset] = deserializeLayout(envelopeLayout, data, { + offset: envelopeOffset, + consumeAll: false, +}); - Inside the `.env` file, add your private key +const [payloadLiteral, payload] = + typeof payloadDet === 'string' + ? [ + payloadDet as PayloadLiteral, + deserializePayload(payloadDet as PayloadLiteral, data, payloadOffset), + ] + : deserializePayload( + payloadDet as PayloadDiscriminator, + data, + payloadOffset + ); - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" +return { + ...header, + ...envelope, + payloadLiteral, + payload, +} satisfies VAA; ``` - !!! note - Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. - -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays - - 1. Create the helpers file +### Registering Custom Payloads - ```bash - mkdir helpers - touch helpers/helpers.ts - ``` +In the Wormhole SDK, payloads rely on layouts to define their binary structure, ensuring consistency and type safety across protocols. Custom payloads extend this functionality, allowing developers to handle protocol-specific features or unique use cases. - 2. Open the `helpers.ts` file and add the following code +To learn how to define and register payloads using layouts, refer to the [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} page for a detailed guide. - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { config } from 'dotenv'; -config(); +## Common Pitfalls & Best Practices -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; -} +When working with the Wormhole SDK layout system, it's important to be aware of a few common issues that can arise. Below are some pitfalls to avoid and best practices to ensure smooth integration. -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} +### Pitfalls to Avoid -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; +#### Defining Sizes for Data Types - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); - } +When defining sizes for each data type, make sure to match the actual data length to the specified size to prevent serialization and deserialization errors: - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - - ``` + - **`uint` and `int`** - the specified size must be large enough to accommodate the data value. For instance, storing a value greater than 255 in a single byte (`uint8`) will fail since it exceeds the byte’s capacity. Similarly, an undersized integer (e.g., specifying 2 bytes for a 4-byte integer) can lead to data loss or deserialization failure + - **`bytes`** - the data must match the specified byte length in the layout. For example, defining a field as 32 bytes (`size: 32`) requires the provided data to be exactly 32 bytes long; otherwise, serialization will fail - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file +```typescript +// Pitfall: Mismatch between the size of data and the defined size in the layout +{ name: 'orderSender', binary: 'bytes', size: 32 } +// If the provided data is not exactly 32 bytes, this will fail +``` -5. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains +#### Incorrectly Defined Arrays - 1. Create the `manual-transfer.ts` file in the `src` directory +Arrays can be fixed-length or length-prefixed, so it’s important to define them correctly. Fixed-length arrays must match the specified length, while length-prefixed arrays need a `lengthSize` field. - ```bash - touch src/manual-transfer.ts - ``` +```typescript +// Pitfall: Array length does not match the expected size +{ name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 } +``` - 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files +### Best Practices - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; - ``` +These best practices and common pitfalls can help prevent bugs and improve the reliability of your implementation when working with layouts in the Wormhole SDK. - - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more - - **`solana`** - this adds support for Solana, a non-EVM chain - - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions +#### Reuse Predefined Layout Items -## Manual Transfers +Rather than defining sizes or types manually, reuse the predefined layout items provided by the Wormhole SDK. These items ensure consistent formatting and enforce strong typing. -In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. +For instance, use the `chainItem` layout for chain IDs or `universalAddressItem` for blockchain addresses: -This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. +```typescript +import { + chainItem, + universalAddressItem, +} from '@wormhole-foundation/sdk-core/layout-items'; -### Set Up the Transfer Environment +const exampleLayout = [ + { name: 'sourceChain', ...chainItem() }, // Use predefined chain ID layout + { name: 'senderAddress', ...universalAddressItem }, // Use universal address layout +] as const; +``` -#### Configure Transfer Details +By leveraging predefined layout items, you reduce redundancy, maintain consistency, and ensure compatibility with Wormhole’s standards. -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. +#### Use Class Instances -1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed +Whenever possible, convert deserialized data into higher-level class instances. This makes it easier to validate, manipulate, and interact with structured data. For example, the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/universalAddress.ts#L17-L59){target=\_blank} class ensures consistent address handling: - ```typescript - const wh = await wormhole('Testnet', [evm, solana]); - ``` - - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. +```typescript +import { UniversalAddress } from '@wormhole-foundation/sdk-core'; -2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them +const deserializedAddress = new UniversalAddress(someBinaryData); +``` - ```typescript - const rcvChain = wh.getChain('Sepolia'); - ``` +Focusing on reusing predefined layout items and converting deserialized data into higher-level abstractions can ensure a more robust and maintainable implementation. -3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains +#### Consistent Error Handling - ```typescript - const destination = await getSigner(rcvChain); - ``` +Always handle errors during both serialization and deserialization. Catching exceptions allows you to log or resolve issues gracefully when working with potentially corrupted or invalid data. -4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK +```typescript +try { + const deserialized = deserializeLayout(fillLayout, data); +} catch (error) { + console.error('Deserialization failed:', error); +} +``` - ```typescript - - ``` +#### Leverage Reusable Layouts -5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself +Creating reusable layouts for commonly repeated structures improves code maintainability and reduces duplication. These layouts can represent fields or combinations of fields frequently encountered in cross-chain communication, such as chain IDs, addresses, and signatures. - ```typescript - - ``` +For example, define a reusable layout for chain IDs and addresses: -#### Initiate the Transfer +```typescript +const commonLayout = [ + { name: 'chainId', binary: 'uint', size: 2 }, + { name: 'address', binary: 'bytes', size: 32 }, +] as const satisfies Layout; -To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. +// Reuse the common layout in different contexts +const exampleLayout = [ + ...commonLayout, + { name: 'sequence', binary: 'uint', size: 8 }, +]; +``` -1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself +By abstracting common elements into a single layout, you ensure consistency across different parts of your application and simplify future updates. - ```typescript - amt, - source.address, - destination.address, - automatic - ); - ``` +## Performance Considerations -2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer +Efficient serialization and deserialization are crucial when handling large amounts of cross-chain data. Below are some strategies and best practices to ensure optimal performance when using Wormhole SDK layouts. - ```typescript - console.log(`Started Transfer: `, srcTxids); - ``` +### Lazy Instantiation -#### Fetch the Circle Attestation (VAA) +Building a discriminator can be resource-intensive for complex or large datasets. The layout structures do not incur significant upfront costs, but deferring the creation of discriminators until needed can improve efficiency. -Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. +```typescript +const lazyDiscriminator = lazyInstantiate(() => layoutDiscriminator(layouts)); +``` +This approach ensures that discriminators are only built when required, helping to optimize performance, especially for complex or conditional layouts. -1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds +## Resources - ```typescript - - ``` +For further learning and practical experience, explore the following resources: -2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout + - **Wormhole TypeScript SDK** - the [Wormhole SDK repository](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} contains the core implementation of layouts, including predefined layout items and utilities like `serializeLayout` and `deserializeLayout` - ```typescript - console.log(`Got Attestation: `, attestIds); - ``` + - **Layout tests repository** - for hands-on experimentation, check out this [layout package repository](https://github.com/nonergodic/layout){target=\_blank}, which provides examples and unit tests to help you better understand serialization, deserialization, and the strong typing mechanism. Running these tests locally is a great way to deepen your understanding of how layouts function in real-world scenarios +--- END CONTENT --- - The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/vaas-protocols/ +--- BEGIN CONTENT --- +--- +title: VAAs and Protocols +description: Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. +categories: Typescript-SDK +--- -#### Complete the Transfer on the Destination Chain +# VAAs and Protocols -Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. +## Introduction -Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain +Wormhole's core functionality revolves around [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs), which are signed messages enabling secure and decentralized communication across chains. This guide focuses on their practical usage within the Wormhole ecosystem, specifically when working with protocol-specific messages in the [TypeScript](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and [Solidity](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} SDKs. -```typescript -console.log(`Completed Transfer: `, dstTxids); +For deeper insights into serialization, deserialization, and protocol design, refer to: - console.log('Circle Transfer status: ', xfer); +- [Data Layouts](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank} for serialization concepts +- [Building Protocols and Payloads](/docs/tools/typescript-sdk/guides/protocols-payloads/){target=\_blank} for designing custom protocol messages - process.exit(0); -``` +This guide will help you understand how to handle VAAs and protocol messages in off-chain and on-chain scenarios. -The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed +## VAA Structure -You can find the full code for the manual USDC transfer script below: +Understanding the structure of VAAs is fundamental to working with Wormhole's SDKs. Each section of the VAA—Header, Envelope, and Payload—serves a specific role: -???- code "`manual-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; +| Section | Description | +|----------|----------------------------------------------------------------------------------------------------------| +| Header | Includes the version and guardian signature information required to verify the VAA | +| Envelope | Contains metadata about the emitted message, such as the emitter chain, emitter address, and timestamp | +| Payload | Represents the actual message, in raw bytes, without a length prefix | -(async function () { - const wh = await wormhole('Testnet', [evm, solana]); +The VAA's body combines the Envelope and Payload. The Wormhole Guardians signed the core data and hashed (using `keccak256`) to generate the VAA's unique identifier. - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); +When integrating protocols like Token Bridge or Wormhole Relayer: - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +- The TypeScript SDK handles VAAs off-chain, focusing on deserialization, validation, and payload extraction before submission +- The Solidity SDK processes VAAs on-chain, using libraries like `VaaLib` to decode and execute protocol actions - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000n; +## VAAs in Protocol Contexts - const automatic = false; +### How VAAs Enable Protocol-Specific Messaging - // Create the Circle transfer object - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); +VAAs are the backbone of Wormhole's cross-chain communication, encapsulating critical protocol payloads that drive actions on different blockchains. Each protocol—such as [Token Bridge](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/tokenBridge){target=\_blank}, [Wormhole Relayer](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/relayer){target=\_blank}, or [Circle CCTP](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/core/definitions/src/protocols/circleBridge){target=\_blank}—uses VAAs to securely transmit its messages across chains. - console.log('Circle Transfer object created:', xfer); +Examples of mapping protocols to VAAs: - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); +| Protocol | Payload Purpose | Example | +|-----------------|-----------------------------------------------------------|------------------------------------| +| Token Bridge | Transfers token data and metadata | Token transfer or redemption | +| Wormhole Relayer| Manages delivery instructions for messages across chains | Delivery fee or refund handling | +| Circle CCTP | Facilitates stablecoin mint-and-burn operations | Circle-issued stablecoin transfer | - // Wait for Circle Attestation (VAA) - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(timeout); - console.log(`Got Attestation: `, attestIds); +Each protocol integrates its payload format into the VAA structure, ensuring consistent message validation and execution across the ecosystem. - // Complete the transfer on the destination chain (Sepolia) - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, dstTxids); +### TypeScript SDK: Off-Chain Handling of VAAs - console.log('Circle Transfer status: ', xfer); +The TypeScript SDK is designed for off-chain operations like reading, validating, and manipulating VAAs before submitting them to a chain. Developers can easily deserialize VAAs to extract protocol payloads and prepare actions such as initiating token transfers or constructing delivery instructions. - process.exit(0); -})(); - ``` +In the example below, we use the real [`envelopeLayout`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/dd6bd2463264680597519285ff559f9e92e85ca7/core/definitions/src/vaa/vaa.ts#L44-L51){target=\_blank} from Wormhole's TS SDK to deserialize and extract essential information like the emitter chain, sequence, and [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank}: -### Run Manual Transfer +```typescript +import { deserializeLayout } from '@wormhole-foundation/sdk-base'; +import { + universalAddressItem, + sequenceItem, +} from '@wormhole-foundation/core/layout-items/index.js'; -To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly +export const envelopeLayout = [ + { name: 'timestamp', binary: 'uint', size: 4 }, + { name: 'nonce', binary: 'uint', size: 4 }, + { name: 'emitterChain', binary: 'uint', size: 2 }, + { name: 'emitterAddress', ...universalAddressItem }, + { name: 'sequence', ...sequenceItem }, + { name: 'consistencyLevel', binary: 'uint', size: 1 }, +] as const satisfies Layout; -```bash -npx ts-node src/manual-transfer.ts +const encodedEnvelope = new Uint8Array([ + /* binary envelope data */ +]); +const deserializedEnvelope = deserializeLayout(envelopeLayout, encodedEnvelope); ``` -This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). +For more details, you can refer to the [parseVAA example](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts){target=\_blank} in the Wormhole SDK repository. -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. +### Solidity SDK: On-Chain Handling of VAAs -### Complete Partial Transfer +The Solidity SDK enables on-chain processing of VAAs directly within smart contracts. This is essential for real-time validation, decoding, and execution of protocol-specific payloads. Developers can use libraries like [`VaaLib`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/e19013d08d1fdf5af9e6344c637e36a270422dd9/src/libraries/VaaLib.sol){target=\_blank} to parse the VAA header and payload, ensuring the message is authentic and consistent with Wormhole's validation. -In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. +Below is an example of parsing an envelope on-chain using the Solidity SDK: -This feature is handy for recovering an incomplete transfer or when debugging. +```solidity +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; -Here’s how you can complete a partial transfer using just the source chain and transaction hash: +import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; -```typescript -wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); +contract EnvelopeParser { + using VaaLib for bytes; - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); + function parseEnvelope( + bytes memory encodedVaa + ) + public + pure + returns ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel + ) + { + // Skip the header and decode the envelope + uint offset = VaaLib.skipVaaHeaderMemUnchecked(encodedVaa, 0); + return VaaLib.decodeVaaEnvelopeMemUnchecked(encodedVaa, offset); + } +} ``` +--- END CONTENT --- -You will need to provide the below requirements to complete the partial transfer: +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/sdk-reference/ +--- BEGIN CONTENT --- +--- +title: Wormhole TS SDK +description: Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. +categories: Typescript-SDK +--- -- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated -- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup +# Wormhole TypeScript SDK -This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. +## Introduction -You can find the full code for the manual USDC transfer script below: +The Wormhole TypeScript SDK is useful for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole. This package bundles together functions, definitions, and constants that streamline the process of connecting chains and completing transfers using Wormhole. The SDK also offers targeted sub-packages for Wormhole-connected platforms, which allow you to add multichain support without creating outsized dependencies. -??? code "`partial-transfer.ts`" - ```typescript - import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; +This section covers all you need to know about the functionality and ease of development offered through the Wormhole TypeScript SDK. Take a tour of the package to discover how it helps make integration easier. Learn more about how the SDK abstracts away complexities around concepts like platforms, contexts, and signers. Finally, you'll find guidance on usage, along with code examples, to show you how to use the tools of the SDK. -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); - // Grab chain Contexts -- these hold a reference to a cached rpc client - const rcvChain = wh.getChain('Sepolia'); +
- // Get signer from local key - const destination = await getSigner(rcvChain); +- :octicons-download-16:{ .lg .middle } **Installation** - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) + --- - // Rebuild the transfer from the source txid - const xfer = await CircleTransfer.from( - wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); + Find installation instructions for both the meta package and installing specific, individual packages - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); + [:custom-arrow: Install the SDK](#installation) - console.log('Circle Transfer status: ', xfer); +- :octicons-book-16:{ .lg .middle } **Concepts** - process.exit(0); -})(); - ``` + --- -## Automatic Transfers + Understand key concepts and how the SDK abstracts them away. Learn more about platforms, chain context, addresses, and signers -The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. + [:custom-arrow: Explore concepts](#concepts) -### Set Up the Transfer Environment +- :octicons-file-code-16:{ .lg .middle } **Usage** -#### Configure Transfer Details + --- -The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you + Guidance on using the SDK to add seamless interchain messaging to your application, including code examples -```typescript + [:custom-arrow: Use the SDK](#usage) -``` +- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** -#### Initiate the Transfer + --- -The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain + Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at availabel methods, classes, interfaces, and definitions -```typescript -amt, - source.address, - destination.address, - automatic - ); -``` + [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} -#### Log Transfer Details +
-After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer +!!! warning + This package is a work in progress. The interface may change, and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} any issues you find. -```typescript -console.log(`Started Transfer: `, srcTxids); +## Installation - process.exit(0); -``` +### Basic -You can find the full code for the automatic USDC transfer script below: +To install the meta package using npm, run the following command in the root directory of your project: -??? code "`automatic-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; +```bash +npm install @wormhole-foundation/sdk +``` -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); +This package combines all the individual packages to make setup easier while allowing for tree shaking. - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); +### Advanced - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +Alternatively, you can install a specific set of published packages individually: - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000_001n; +??? interface "`sdk-base` - exposes constants" - const automatic = true; + ```sh + npm install @wormhole-foundation/sdk-base + ``` - // Create the Circle transfer object (USDC-only) - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); +??? interface "`sdk-definitions` - exposes contract interfaces, basic types, and VAA payload definitions" - console.log('Circle Transfer object created:', xfer); + ```sh + npm install @wormhole-foundation/sdk-definitions + ``` - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); +??? interface "`sdk-evm` - exposes EVM-specific utilities" - process.exit(0); -})(); + ```sh + npm install @wormhole-foundation/sdk-evm ``` -### Run Automatic Transfer +??? interface "`sdk-evm-tokenbridge` - exposes the EVM Token Bridge protocol client" -Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: + ```sh + npm install @wormhole-foundation/sdk-evm-tokenbridge + ``` -```bash -npx ts-node src/automatic-transfer.ts -``` +## Usage -The automatic relayer will take care of fetching the attestation and completing the transfer for you. +Getting your integration started is simple. First, import Wormhole: -## Resources +```ts +import { wormhole } from '@wormhole-foundation/sdk'; -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. +import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; +import algorand from '@wormhole-foundation/sdk/algorand'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helpers/index.js'; -## Conclusion +(async function () { + const wh = await wormhole('Testnet', [ + evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); -In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. + const ctx = wh.getChain('Solana'); -By following these steps, you've learned how to: + const rcv = wh.getChain('Algorand'); -- Set up cross-chain transfers for native USDC between supported chains -- Handle both manual and automatic relaying of transactions -- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer ---- END CONTENT --- + const sender = await getSigner(ctx); + const receiver = await getSigner(rcv); -Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/ ---- BEGIN CONTENT --- ---- -title: Wormholescan API Tutorials -description: Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. ---- + // Get a Token Bridge contract client on the source + const sndTb = await ctx.getTokenBridge(); -# Wormholescan API + // Send the native token of the source chain + const tokenId = Wormhole.tokenId(ctx.chain, 'native'); -Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. + // Bigint amount using `amount` module + const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); -## Tutorials + // Create a transaction stream for transfers + const transfer = sndTb.transfer( + sender.address.address, + receiver.address, + tokenId.address, + amt + ); -
+ // Sign and send the transaction + const txids = await signSendWait(ctx, transfer, sender.signer); + console.log('Sent: ', txids); -- :octicons-repo-16:{ .lg .middle } **Replace Outdated Signatures in VAAs** + // Get the Wormhole message ID from the transaction + const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); + console.log('Wormhole Messages: ', whm); - --- + const vaa = await wh.getVaa( + // Wormhole Message ID + whm!, + // Protocol:Payload name to use for decoding the VAA payload + 'TokenBridge:Transfer', + // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available + 60_000 + ); - Learn how to fetch VAAs, verify their validity, and replace outdated signatures using the Wormholescan API and Wormhole SDK. + // Now get the token bridge on the redeem side + const rcvTb = await rcv.getTokenBridge(); - [:custom-arrow: Start tutorial](/docs/products/messaging/tutorials/replace-signatures/) + // Create a transaction stream for redeeming + const redeem = rcvTb.redeem(receiver.address.address, vaa!); -
+ // Sign and send the transaction + const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); + console.log('Sent: ', rcvTxids); -## Additional Resources + // Now check if the transfer is completed according to + // the destination token bridge + const finished = await rcvTb.isTransferCompleted(vaa!); + console.log('Transfer completed: ', finished); +})(); +``` -
+Then, import each of the ecosystem [platforms](#platforms) that you wish to support: -- :octicons-book-16:{ .lg .middle } **Wormholescan** +```ts +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +``` - --- - Wormholescan is a blockchain explorer for tracking transactions, VAAs, and cross-chain activity. Its API provides programmatic access to transaction data, network analytics, and more. +To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: - [:custom-arrow: Visit Wormholescan](https://wormholescan.io/){target=\_blank} +```ts +evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); +``` -
---- END CONTENT --- +With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ ---- BEGIN CONTENT --- ---- -title: Replace Outdated Signatures in VAAs -description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. ---- +```ts -# Replace Outdated Signatures in VAAs +``` -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} +You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. -## Introduction +```ts +// Wormhole Message ID + whm!, + // Protocol:Payload name to use for decoding the VAA payload + 'TokenBridge:Transfer', + // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available + 60_000 + ); +``` -Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. +??? code "View the complete script" + ```ts + import { wormhole } from '@wormhole-foundation/sdk'; -However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. +import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; +import algorand from '@wormhole-foundation/sdk/algorand'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helpers/index.js'; -Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. +(async function () { + const wh = await wormhole('Testnet', [ + evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); -In this tutorial, you'll build a script from scratch to: + const ctx = wh.getChain('Solana'); -- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} -- Validate its signatures against the latest Guardian set -- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} -- Output a valid VAA ready for submission + const rcv = wh.getChain('Algorand'); -By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. + const sender = await getSigner(ctx); + const receiver = await getSigner(rcv); -## Prerequisites + // Get a Token Bridge contract client on the source + const sndTb = await ctx.getTokenBridge(); -Before you begin, ensure you have the following: + // Send the native token of the source chain + const tokenId = Wormhole.tokenId(ctx.chain, 'native'); - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + // Bigint amount using `amount` module + const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); -## Project Setup + // Create a transaction stream for transfers + const transfer = sndTb.transfer( + sender.address.address, + receiver.address, + tokenId.address, + amt + ); -In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. + // Sign and send the transaction + const txids = await signSendWait(ctx, transfer, sender.signer); + console.log('Sent: ', txids); -1. **Create the project** - set up the directory and navigate into it + // Get the Wormhole message ID from the transaction + const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); + console.log('Wormhole Messages: ', whm); - ```bash - mkdir wormhole-scan-api-demo - cd wormhole-scan-api-demo - ``` + const vaa = await wh.getVaa( + // Wormhole Message ID + whm!, + // Protocol:Payload name to use for decoding the VAA payload + 'TokenBridge:Transfer', + // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available + 60_000 + ); -2. **Initialize a Node.js project** - generate a `package.json` file + // Now get the token bridge on the redeem side + const rcvTb = await rcv.getTokenBridge(); - ```bash - npm init -y - ``` + // Create a transaction stream for redeeming + const redeem = rcvTb.redeem(receiver.address.address, vaa!); -3. **Set up TypeScript** - create a `tsconfig.json` file + // Sign and send the transaction + const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); + console.log('Sent: ', rcvTxids); - ```bash - touch tsconfig.json + // Now check if the transfer is completed according to + // the destination token bridge + const finished = await rcvTb.isTransferCompleted(vaa!); + console.log('Transfer completed: ', finished); +})(); ``` - Then, add the following configuration: +Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. - ```json title="tsconfig.json" - { - "compilerOptions": { - "target": "es2016", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - } -} +```ts +const wh = await wormhole('Testnet', [solana], { + chains: { + Solana: { + contracts: { + coreBridge: '11111111111111111111111111111', + }, + rpc: 'https://api.devnet.solana.com', + }, + }, +}); +``` + +??? code "View the complete script" + ```ts + import { wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +(async function () { + const wh = await wormhole('Testnet', [solana], { + chains: { + Solana: { + contracts: { + coreBridge: '11111111111111111111111111111', + }, + rpc: 'https://api.devnet.solana.com', + }, + }, + }); + console.log(wh.config.chains.Solana); +})(); ``` -4. **Install dependencies** - add the required packages +## Concepts - ```bash - npm install @wormhole-foundation/sdk axios web3 tsx @types/node - ``` +Understanding several higher-level Wormhole concepts and how the SDK abstracts them away will help you use the tools most effectively. The following sections will introduce and discuss the concepts of platforms, chain contexts, addresses, signers, and protocols, how they are used in the Wormhole context, and how the SDK helps ease development in each conceptual area. - - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions - - `axios` - makes HTTP requests to the Wormholescan API - - `web3` - interacts with Ethereum transactions and contracts - - `tsx` - executes TypeScript files without compilation - - `@types/node` - provides Node.js type definitions +### Platforms -5. **Create the project structure** - set up the required directories and files +While every chain has unique attributes, chains from the same platform typically have standard functionalities they share. The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: - ```bash - mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts - mkdir -p src/helpers && touch src/helpers/vaaHelper.ts - mkdir -p src/scripts && touch scripts/replaceSignatures.ts - ``` +- Protocols, such as [Wormhole core](#wormhole-core), preconfigured to suit the selected platform +- Definitions and configurations for types, signers, addresses, and chains +- Helpers configured for dealing with unsigned transactions on the selected platform - - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures - - **`src/helpers/*`** - contains utility functions - - **`src/scripts/*`** - contains scripts for fetching and replacing signatures +These modules also import and expose essential functions and define types or constants from the chain's native ecosystem to reduce the dependencies needed to interact with a chain using Wormhole. Rather than installing the entire native package for each desired platform, you can install a targeted package of standardized functions and definitions essential to connecting with Wormhole, keeping project dependencies as slim as possible. -6. **Set variables** - define key constants in `src/config/constants.ts` - ```bash title="src/config/constants.ts" - export const RPC = 'https://ethereum-rpc.publicnode.com'; +Wormhole currently supports the following platforms: -export const ETH_CORE = - '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase(); +- EVM +- Solana +- Cosmos +- Sui +- Aptos +- Algorand -export const WORMHOLESCAN_API = 'https://api.wormholescan.io/v1'; +See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. -export const LOG_MESSAGE_PUBLISHED_TOPIC = - '0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2'; +### Chain Context -export const TXS = [ - '0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367', - '0x3c989a6bb40dcd4719453fbe7bbac420f23962c900ae75793124fc9cc614368c', -]; - ``` +The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. - - **`RPC`** - endpoint for interacting with an Ethereum RPC node - - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs - - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets - - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts - - **`TXS`** - list of example transaction hashes that will be used for testing +```ts +const srcChain = wh.getChain(senderAddress.chain); +const dstChain = wh.getChain(receiverAddress.chain); -7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs +const tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'> +srcChain.getRpcClient(); // => RpcClient<'Evm'> +``` - ```typescript title="src/config/layouts.ts" - export const PARSE_AND_VERIFY_VM_ABI = { - inputs: [{ internalType: 'bytes', name: 'encodedVM', type: 'bytes' }], - name: 'parseAndVerifyVM', - outputs: [ - { - components: [ - { internalType: 'uint8', name: 'version', type: 'uint8' }, - { internalType: 'uint32', name: 'timestamp', type: 'uint32' }, - { internalType: 'uint32', name: 'nonce', type: 'uint32' }, - { internalType: 'uint16', name: 'emitterChainId', type: 'uint16' }, - { internalType: 'bytes32', name: 'emitterAddress', type: 'bytes32' }, - { internalType: 'uint64', name: 'sequence', type: 'uint64' }, - { internalType: 'uint8', name: 'consistencyLevel', type: 'uint8' }, - { internalType: 'bytes', name: 'payload', type: 'bytes' }, - { internalType: 'uint32', name: 'guardianSetIndex', type: 'uint32' }, - { - components: [ - { internalType: 'bytes32', name: 'r', type: 'bytes32' }, - { internalType: 'bytes32', name: 's', type: 'bytes32' }, - { internalType: 'uint8', name: 'v', type: 'uint8' }, - { internalType: 'uint8', name: 'guardianIndex', type: 'uint8' }, - ], - internalType: 'struct Structs.Signature[]', - name: 'signatures', - type: 'tuple[]', - }, - { internalType: 'bytes32', name: 'hash', type: 'bytes32' }, - ], - internalType: 'struct Structs.VM', - name: 'vm', - type: 'tuple', - }, - { internalType: 'bool', name: 'valid', type: 'bool' }, - { internalType: 'string', name: 'reason', type: 'string' }, - ], - stateMutability: 'view', - type: 'function', -}; - ``` +### Addresses -## Create VAA Handling Functions +The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. + +```ts +// It's possible to convert a string address to its Native address +const ethAddr: NativeAddress<'Evm'> = toNative('Ethereum', '0xbeef...'); -In this section, we'll create a series of helper functions in the `src/helpers/vaaHelper.ts` file that will retrieve and verify VAAs and fetch and replace outdated Guardian signatures to generate a correctly signed VAA. +// A common type in the SDK is the `ChainAddress` which provides +// the additional context of the `Chain` this address is relevant for +const senderAddress: ChainAddress = Wormhole.chainAddress( + 'Ethereum', + '0xbeef...' +); +const receiverAddress: ChainAddress = Wormhole.chainAddress( + 'Solana', + 'Sol1111...' +); -To get started, import the necessary dependencies: +// Convert the ChainAddress back to its canonical string address format +const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' -```typescript title="src/helpers/vaaHelper.ts" -import { eth } from 'web3'; -import { - deserialize, - serialize, - VAA, - Signature, -} from '@wormhole-foundation/sdk'; -import { - RPC, - ETH_CORE, - LOG_MESSAGE_PUBLISHED_TOPIC, - WORMHOLESCAN_API, -} from '../config/constants'; -import { PARSE_AND_VERIFY_VM_ABI } from '../config/layouts'; +// Or if the ethAddr above is for an emitter and you need the UniversalAddress +const emitterAddr = ethAddr.toUniversalAddress().toString(); ``` -### Fetch a VAA ID from a Transaction +### Tokens -To retrieve a VAA, we first need to get its VAA ID from a transaction hash. This ID allows us to fetch the full VAA later. -The VAA ID is structured as follows: +Similar to the `ChainAddress` type, the `TokenId` type provides the chain and address of a given token. The following snippet introduces `TokenId`, a way to uniquely identify any token, whether it's a standard token or a blockchain's native currency (like ETH for Ethereum). -```bash -chain/emitter/sequence +Wormhole uses their contract address to create a `TokenId` for standard tokens. For native currencies, Wormhole uses the keyword `native` instead of an address. This makes it easy to work with any type of token consistently. + +Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. + +```ts +const sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...'); + +const gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native'); + +const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' ``` - - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) - - `emitter` - the contract address that emitted the VAA - - `sequence` - a unique identifier for the event +### Signers -We must assemble the ID correctly since this is the format the Wormholescan API expects when querying VAAs. +Certain methods of signing transactions require a `Signer` interface in the SDK. Depending on the specific requirements, this interface can be fulfilled by either a `SignOnlySigner` or a `SignAndSendSigner`. A signer can be created by wrapping an offline or web wallet. -Follow the below steps to process the transaction logs and construct the VAA ID: +A `SignOnlySigner` is used when the signer isn't connected to the network or prefers not to broadcast transactions themselves. It accepts an array of unsigned transactions and returns an array of signed and serialized transactions. Before signing, the transactions may be inspected or altered. It's important to note that the serialization process is chain-specific. Refer to the testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank} or [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for an example of how to implement a signer for a specific chain or platform. -1. **Get the transaction receipt** - iterate over the array of transaction hashes and fetch the receipt to access its logs +Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. -2. **Find the Wormhole event** - iterate over the transaction logs and check for events emitted by the Wormhole Core contract. Look specifically for `LogMessagePublished` events, which indicate a VAA was created +```ts +export type Signer = SignOnlySigner | SignAndSendSigner; -3. **Extract the emitter and sequence number** - if a matching event is found, extract the emitter address from `log.topics[1]` and remove the `0x` prefix. Then, the sequence number from `log.data` is extracted, converting it from hex to an integer +export interface SignOnlySigner { + chain(): ChainName; + address(): string; + // Accept an array of unsigned transactions and return + // an array of signed and serialized transactions. + // The transactions may be inspected or altered before + // signing. + sign(tx: UnsignedTransaction[]): Promise; +} -4. **Construct the VAA ID** - format the extracted data in `chain/emitter/sequence` format +export interface SignAndSendSigner { + chain(): ChainName; + address(): string; + // Accept an array of unsigned transactions and return + // an array of transaction ids in the same order as the + // unsignedTransactions array. + signAndSend(tx: UnsignedTransaction[]): Promise; +} +``` -```typescript title="src/helpers/vaaHelper.ts" -const vaaIds: string[] = []; +#### Set Up a Signer with Ethers.js - for (const tx of txHashes) { - try { - const result = ( - await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_getTransactionReceipt', - params: [tx], - }) - ).data.result; +To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: - if (!result) - throw new Error(`Unable to fetch transaction receipt for ${tx}`); +```javascript +import { ethers } from 'ethers'; - for (const log of result.logs) { - if ( - log.address === ETH_CORE && - log.topics?.[0] === LOG_MESSAGE_PUBLISHED_TOPIC - ) { - const emitter = log.topics[1].substring(2); - const seq = BigInt(log.data.substring(0, 66)).toString(); - vaaIds.push(`2/${emitter}/${seq}`); - } - } - } catch (error) { - console.error(`Error processing ${tx}:`, error); - } - } +// Update the following variables +const rpcUrl = 'INSERT_RPC_URL'; +const privateKey = 'INSERT_PRIVATE_KEY'; +const toAddress = 'INSERT_RECIPIENT_ADDRESS'; - return vaaIds; -} -``` +// Set up a provider and signer +const provider = new ethers.JsonRpcProvider(rpcUrl); +const signer = new ethers.Wallet(privateKey, provider); -???- code "Try it out: VAA ID retrieval" - If you want to try out the function before moving forward, create a test file inside the `test` directory: +// Example: Signing and sending a transaction +async function sendTransaction() { + const tx = { + to: toAddress, + value: ethers.parseUnits('0.1'), // Sending 0.1 ETH + gasPrice: await provider.getGasPrice(), + gasLimit: ethers.toBeHex(21000), + }; - 1. **Create the directory and file** - add a script to call `fetchVaaId` and print the result + const transaction = await signer.sendTransaction(tx); + console.log('Transaction hash:', transaction.hash); +} +sendTransaction(); +``` - ```bash - mkdir -p test - touch test/fetchVaaId.run.ts - ``` - 2. **Add the function call** + - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions - ```typescript title="test/fetchVaaId.run.ts" - import { fetchVaaId } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; + - **`signer`** - represents the account that will sign the transaction. In this case, you’re creating a signer using the private key associated with the account. The signer is responsible for authorizing transactions by digitally signing them with the private key -const testFetchVaaId = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); + - **`Wallet`** - combines both the provider (for blockchain interaction) and the signer (for transaction authorization), allowing you to sign and send transactions programmatically - if (vaaIds.length > 0) { - console.log(`Transaction: ${tx}`); - vaaIds.forEach((vaaId) => console.log(`VAA ID: ${vaaId}`)); - } else { - console.log(`No VAA ID found for transaction: ${tx}`); - } - } -}; +These components work together to create, sign, and submit a transaction to the blockchain. -testFetchVaaId(); - ``` +???- tip "Managing Private Keys Securely" + Handling private keys is unavoidable, so it’s crucial to manage them securely. Here are some best practices: - 3. **Run the script** + - **Use environment variables** - avoid hardcoding private keys in your code. Use environment variables or secret management tools to inject private keys securely + - **Hardware wallets** - for production environments, consider integrating hardware wallets to keep private keys secure while allowing programmatic access through the SDK - ```bash - npx tsx test/fetchVaaId.run.ts - ``` +### Protocols - If successful, the output will be: +While Wormhole is a Generic Message Passing (GMP) protocol, several protocols have been built to provide specific functionality. If available, each protocol will have a platform-specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain. -
-npx tsx test/fetchVaaId.run.ts - -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -VAA ID: 2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/164170 - -
+#### Wormhole Core - If no VAA ID is found, the script will log an error message. +The core protocol underlies all Wormhole activity. This protocol is responsible for emitting the message containing the information necessary to perform bridging, including the [emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter){target=\_blank}, the [sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence){target=\_blank} for the message, and the payload of the message itself. -### Fetch the Full VAA +The following example demonstrates sending and verifying a message using the Wormhole Core protocol on Solana. -Now that you have the VAA ID, we can use it to fetch the full VAA payload from the Wormholescan API. This payload contains the VAA bytes, which will later be used for signature validation. +First, initialize a Wormhole instance for the Testnet environment, specifically for the Solana chain. Then, obtain a signer and its associated address, which will be used to sign transactions. -Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload. +Next, get a reference to the core messaging bridge, which is the main interface for interacting with Wormhole's cross-chain messaging capabilities. +The code then prepares a message for publication. This message includes: -```typescript title="src/helpers/vaaHelper.ts" -vaaIds: string[] -): Promise<{ id: string; vaaBytes: string }[]> { - const results: { id: string; vaaBytes: string }[] = []; +- The sender's address +- The message payload (in this case, the encoded string `lol`) +- A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) +- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) - for (const id of vaaIds) { - try { - const response = await axios.get(`${WORMHOLESCAN_API}/signed_vaa/${id}`); - const vaaBytes = response.data.vaaBytes; - results.push({ id, vaaBytes }); - } catch (error) { - console.error(`Error fetching VAA for ${id}:`, error); - } - } - return results; -} -``` +After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. -???- code "Try it out: VAA retrieval" - If you want to try the function before moving forward, create a script inside the `test` directory +The code then waits for the Wormhole network to process and sign the message, turning it into a Verified Action Approval (VAA). This VAA is retrieved in a `Uint8Array` format, with a timeout of 60 seconds. - 1. **Create the script file** +Lastly, the code will demonstrate how to verify the message on the receiving end. A verification transaction is prepared using the original sender's address and the VAA, and finally, this transaction is signed and sent. - ```bash - touch test/fetchVaa.run.ts - ``` +???+ code "View the complete script" + ```ts + import { encoding, signSendWait, wormhole } from '@wormhole-foundation/sdk'; +import { getSigner } from './helpers/index.js'; +import solana from '@wormhole-foundation/sdk/solana'; +import evm from '@wormhole-foundation/sdk/evm'; - 2. **Add the function call** +(async function () { + const wh = await wormhole('Testnet', [solana, evm]); - ```typescript title="test/fetchVaa.run.ts" - import { fetchVaaId, fetchVaa } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; + const chain = wh.getChain('Avalanche'); + const { signer, address } = await getSigner(chain); -const testFetchVaa = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); + // Get a reference to the core messaging bridge + const coreBridge = await chain.getWormholeCore(); - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } + // Generate transactions, sign and send them + const publishTxs = coreBridge.publishMessage( + // Address of sender (emitter in VAA) + address.address, + // Message to send (payload in VAA) + encoding.bytes.encode('lol'), + // Nonce (user defined, no requirement for a specific value, useful to provide a unique identifier for the message) + 0, + // ConsistencyLevel (ie finality of the message, see wormhole docs for more) + 0 + ); + // Send the transaction(s) to publish the message + const txids = await signSendWait(chain, publishTxs, signer); - for (const vaaId of vaaIds) { - const vaaBytes = await fetchVaa([vaaId]); + // Take the last txid in case multiple were sent + // The last one should be the one containing the relevant + // event or log info + const txid = txids[txids.length - 1]; - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Bytes: ${ - vaaBytes.length > 0 ? vaaBytes[0].vaaBytes : 'Not found' - }` - ); - } - } -}; + // Grab the wormhole message id from the transaction logs or storage + const [whm] = await chain.parseTransaction(txid!.txid); -testFetchVaa(); - ``` + // Wait for the vaa to be signed and available with a timeout + const vaa = await wh.getVaa(whm!, 'Uint8Array', 60_000); + console.log(vaa); - 3. **Run the script** + // Note: calling verifyMessage manually is typically not a useful thing to do + // As the VAA is typically submitted to the counterpart contract for + // A given protocol and the counterpart contract will verify the VAA + // This is simply for demo purposes + const verifyTxs = coreBridge.verifyMessage(address.address, vaa!); + console.log(await signSendWait(chain, verifyTxs, signer)); +})(); + ``` - ```bash - npx tsx test/fetchVaa.run.ts - ``` +The payload contains the information necessary to perform whatever action is required based on the protocol that uses it. - If successful, the output will be: +#### Token Bridge -
-npx tsx test/fetchVaa.run.ts - -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -VAA Bytes: AQAAAAMNANQSwD/HRPcKp7Yxypl1ON8dZeMBzgYJrd2KYz6l9Tq9K9fj72fYJgkMeMaB9h... - -
+The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. - If no VAA is found, the script will log an error message. +```ts +import { signSendWait } from '@wormhole-foundation/sdk'; -### Validate VAA Signatures +const tb = await srcChain.getTokenBridge(); -Now, we need to verify its validity. A VAA is only considered valid if it contains signatures from currently active Guardians and is correctly verified by the Wormhole Core contract. +const token = '0xdeadbeef...'; +const txGenerator = tb.createAttestation(token); +const txids = await signSendWait(srcChain, txGenerator, src.signer); +``` -Open `src/helpers/vaaHelper.ts` and add the `checkVaaValidity()` function. This function verifies whether a VAA is valid by submitting it to an Ethereum RPC node and checking for outdated signatures. +Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. -Follow these steps to implement the function: +## Transfers -1. **Prepare the VAA for verification** - construct the VAA payload in a format that can be sent to the Wormhole Core contract +While using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens. -2. **Send an `eth_call` request** - submit the VAA to an Ethereum RPC node, calling the `parseAndVerifyVM` function on the Wormhole Core contract +The `WormholeTransfer` interface provides a convenient abstraction to encapsulate the steps involved in a cross-chain transfer. -3. **Decode the response** - check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them +### Token Transfers -```typescript title="src/helpers/vaaHelper.ts" -try { - const vaa = Buffer.from(vaaBytes, 'base64'); - vaa[4] = 4; // Set guardian set index to 4 +Performing a token transfer is trivial for any source and destination chains. You can create a new `Wormhole` object to make objects like `TokenTransfer` and `CircleTransfer`, to transfer tokens between chains. - const result = ( - await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [ - `0x${vaa.toString('hex')}`, - ]), - }, - 'latest', - ], - }) - ).data.result; +The following example demonstrates the process of initiating and completing a token transfer. It starts by creating a `TokenTransfer` object, which tracks the transfer's state throughout its lifecycle. The code then obtains a quote for the transfer, ensuring the amount is sufficient to cover fees and any requested native gas. - const decoded = eth.abi.decodeParameters( - PARSE_AND_VERIFY_VM_ABI.outputs, - result - ); - console.log( - `${decoded.valid ? '✅' : '❌'} VAA Valid: ${decoded.valid}${ - decoded.valid ? '' : `, Reason: ${decoded.reason}` - }` - ); +The transfer process is divided into three main steps: - return { valid: decoded.valid, reason: decoded.reason }; - } catch (error) { - console.error(`Error checking VAA validity:`, error); - return { valid: false, reason: 'RPC error' }; - } -} -``` +1. Initiating the transfer on the source chain +2. Waiting for the transfer to be attested (if not automatic) +3. Completing the transfer on the destination chain -???- code "Try it out: VAA Validity" - If you want to try the function before moving forward, create a script inside the `test` directory +For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. - 1. **Create the script file** +```ts +const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.delivery?.automatic ?? false, + route.payload, + route.delivery?.nativeGas + ); - ```bash - touch test/checkVaaValidity.run.ts - ``` + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); + console.log(quote); - 2. **Add the function call** + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; - ```typescript title="test/checkVaaValidity.run.ts" - import { - fetchVaaId, - fetchVaa, - checkVaaValidity, -} from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; + // 1) Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Started transfer: `, srcTxids); -const testCheckVaaValidity = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); + // If automatic, we're done + if (route.delivery?.automatic) return xfer; - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } + // 2) Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + const attestIds = await xfer.fetchAttestation(60_000); + console.log(`Got Attestation: `, attestIds); - for (const vaaId of vaaIds) { - const vaaData = await fetchVaa([vaaId]); + // 3) Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +``` - if (vaaData.length === 0 || !vaaData[0].vaaBytes) { - console.log(`VAA not found for ID: ${vaaId}`); - continue; - } +??? code "View the complete script" + ```ts hl_lines="122" + import { + Chain, + Network, + TokenId, + TokenTransfer, + Wormhole, + amount, + isTokenId, + wormhole, +} from '@wormhole-foundation/sdk'; - const result = await checkVaaValidity(vaaData[0].vaaBytes); - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Validity:`, - result - ); - } - } -}; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { SignerStuff, getSigner, waitLog } from './helpers/index.js'; -testCheckVaaValidity(); - ``` +(async function () { + // Init Wormhole object, passing config for which network + // to use (e.g. Mainnet/Testnet) and what Platforms to support + const wh = await wormhole('Testnet', [evm, solana]); - 3. **Run the script** + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Solana'); - ```bash - npx tsx test/checkVaaValidity.run.ts - ``` + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); - If the VAA is valid, the output will be: + // A TokenId is just a `{chain, address}` pair and an alias for ChainAddress + // The `address` field must be a parsed address. + // You can get a TokenId (or ChainAddress) prepared for you + // by calling the static `chainAddress` method on the Wormhole class. + // e.g. + // wAvax on Solana + // const token = Wormhole.tokenId("Solana", "3Ftc5hTz9sG4huk79onufGiebJNDMZNL8HYgdMJ9E7JR"); + // wSol on Avax + // const token = Wormhole.tokenId("Avalanche", "0xb10563644a6AB8948ee6d7f5b0a1fb15AaEa1E03"); -
-npx tsx test/checkVaaValidity.run.ts - -✅ VAA Valid: true - -
+ // Normalized given token decimals later but can just pass bigints as base units + // Note: The Token bridge will dedust past 8 decimals + // This means any amount specified past that point will be returned + // To the caller + const amt = '0.05'; - If invalid, the output will include the reason: + // With automatic set to true, perform an automatic transfer. This will invoke a relayer + // Contract intermediary that knows to pick up the transfers + // With automatic set to false, perform a manual transfer from source to destination + // Of the token + // On the destination side, a wrapped version of the token will be minted + // To the address specified in the transfer VAA + const automatic = false; -
-npx tsx test/checkVaaValidity.run.ts - -❌ VAA Valid: false, Reason: VM signature invalid -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 - -
+ // The Wormhole relayer has the ability to deliver some native gas funds to the destination account + // The amount specified for native gas will be swapped for the native gas token according + // To the swap rate provided by the contract, denominated in native gas tokens + const nativeGas = automatic ? '0.01' : undefined; -### Fetch Observations (VAA Signatures) + // Get signer from local key but anything that implements + // Signer interface (e.g. wrapper around web wallet) should work + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -Before replacing outdated signatures, we need to fetch the original VAA signatures from Wormholescan. This allows us to compare them with the latest Guardian set and determine which ones need updating. + // Used to normalize the amount to account for the tokens decimals + const decimals = isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : sendChain.config.nativeTokenDecimals; -Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to query the Wormholescan API for observations related to a given VAA. Format the response by converting Guardian addresses to lowercase for consistency, and return an empty array if an error occurs. + // Set this to true if you want to perform a round trip transfer + const roundTrip: boolean = false; -```typescript title="src/helpers/vaaHelper.ts" -try { - console.log(`Fetching observations`); + // Set this to the transfer txid of the initiating transaction to recover a token transfer + // And attempt to fetch details about its progress. + let recoverTxid = undefined; - const response = await axios.get( - `https://api.wormholescan.io/api/v1/observations/${vaaId}` - ); + // Finally create and perform the transfer given the parameters set above + const xfer = !recoverTxid + ? // Perform the token transfer + await tokenTransfer( + wh, + { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + delivery: { + automatic, + nativeGas: nativeGas + ? amount.units(amount.parse(nativeGas, decimals)) + : undefined, + }, + }, + roundTrip + ) + : // Recover the transfer from the originating txid + await TokenTransfer.from(wh, { + chain: source.chain.chain, + txid: recoverTxid, + }); - return response.data.map((obs: any) => ({ - guardianAddr: obs.guardianAddr.toLowerCase(), - signature: obs.signature, - })); - } catch (error) { - console.error(`Error fetching observations:`, error); - return []; - } -} -``` + const receipt = await waitLog(wh, xfer); -???- code "Try it out: Fetch Observations" - If you want to try the function before moving forward, create a script inside the `test` directory + // Log out the results + console.log(receipt); +})(); - 1. **Create the script file** +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + delivery?: { + automatic: boolean; + nativeGas?: bigint; + }; + payload?: Uint8Array; + }, + roundTrip?: boolean +): Promise> { + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.delivery?.automatic ?? false, + route.payload, + route.delivery?.nativeGas + ); - ```bash - touch test/fetchObservations.run.ts - ``` + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); + console.log(quote); - 2. **Add the function call** + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; - ```typescript title="test/fetchObservations.run.ts" - import { fetchVaaId, fetchObservations } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; + // 1) Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Started transfer: `, srcTxids); -const testFetchObservations = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); + // If automatic, we're done + if (route.delivery?.automatic) return xfer; - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } + // 2) Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + const attestIds = await xfer.fetchAttestation(60_000); + console.log(`Got Attestation: `, attestIds); - for (const vaaId of vaaIds) { - const observations = await fetchObservations(vaaId); + // 3) Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); - if (observations.length === 0) { - console.log(`No observations found for VAA ID: ${vaaId}`); - continue; - } + // If no need to send back, dip + if (!roundTrip) return xfer; - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nObservations:`, - observations - ); - } - } -}; + const { destinationToken: token } = quote; + return await tokenTransfer(wh, { + ...route, + token: token.token, + amount: token.amount, + source: route.destination, + destination: route.source, + }); +} + + ``` -testFetchObservations(); - ``` +Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. - 3. **Run the script** +### Native USDC Transfers - ```bash - npx tsx test/fetchObservations.run.ts - ``` +You can also transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. Please note that if the transfer is set to `Automatic` mode, a fee for performing the relay will be included in the quote. This fee is deducted from the total amount requested to be sent. For example, if the user wishes to receive `1.0` on the destination, the amount sent should be adjusted to `1.0` plus the relay fee. The same principle applies to native gas drop offs. - If successful, the output will be: +In the following example, the `wh.circleTransfer` function is called with several parameters to set up the transfer. It takes the amount to be transferred (in the token's base units), the sender's chain and address, and the receiver's chain and address. The function also allows specifying whether the transfer should be automatic, meaning it will be completed without further user intervention. -
-npx tsx test/fetchObservations.run.ts - -Fetching observations -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -Observations: [ { guardianAddr: '0xda798f6896a3331f64b48c12d1d57fd9cbe70811', signature: - 'ZGFlMDYyOGNjZjFjMmE0ZTk5YzE2OThhZjAzMDM4NzZlYTM1OWMxMzczNDA3YzdlMDMxZTkyNzk0ODkwYjRiYjRiOWFmNzM3NjRiMzIyOTE0ZTQwYzNlMjllMWEzNmM2NTc3ZDc5ZTdhNTM2MzA5YjA4YjExZjE3YzE3MDViNWIwMQ==' - }, { guardianAddr: '0x74a3bf913953d695260d88bc1aa25a4eee363ef0', signature: - 'MzAyOTU4OGU4MWU0ODc0OTAwNDU3N2EzMGZlM2UxMDJjOWYwMjM0NWVhY2VmZWQ0ZGJlNTFkNmI3YzRhZmQ5ZTNiODFjNTg3MDNmYzUzNmJiYWFiZjNlODc1YTY3OTQwMGE4MmE3ZjZhNGYzOGY3YmRmNDNhM2VhNGQyNWNlNGMwMA==' - }, -...] - -
+An optional payload can be included with the transfer, though it's set to undefined in this case. Finally, if the transfer is automatic, you can request that native gas (the blockchain's native currency used for transaction fees) be sent to the receiver along with the transferred tokens. - If no observations are found, the script will log an error message. +When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. -### Fetch the Latest Guardian Set +```ts +// Amount as bigint (base units) + req.amount, + // Sender chain/address + src.address, + // Receiver chain/address + dst.address, + // Automatic delivery boolean + req.automatic, + // Payload to be sent with the transfer + undefined, + // If automatic, native gas can be requested to be sent to the receiver + req.nativeGas + ); -Now that we have the original VAA signatures, we must fetch the latest Guardian set from Wormholescan. This will allow us to compare the stored signatures with the current Guardians and determine which signatures need replacing. + // Note, if the transfer is requested to be Automatic, a fee for performing the relay + // will be present in the quote. The fee comes out of the amount requested to be sent. + // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. + // The same applies for native gas dropoff + const quote = await CircleTransfer.quoteTransfer( + src.chain, + dst.chain, + xfer.transfer + ); + console.log('Quote', quote); -Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set. + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(src.signer); + console.log(`Started Transfer: `, srcTxids); -```typescript title="src/helpers/vaaHelper.ts" -export async function fetchGuardianSet() { - try { - console.log('Fetching current guardian set'); + if (req.automatic) { + const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); + console.log(`Finished relay: `, relayStatus); + return; + } - const response = await axios.get(`${WORMHOLESCAN_API}/guardianset/current`); - const guardians = response.data.guardianSet.addresses.map((addr: string) => - addr.toLowerCase() - ); - const guardianSet = response.data.guardianSet.index; + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(60_000); + console.log(`Got Attestation: `, attestIds); - return [guardians, guardianSet]; - } catch (error) { - console.error('Error fetching guardian set:', error); - return []; - } + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(dst.signer); + console.log(`Completed Transfer: `, dstTxids); } ``` -???- code "Try it out: Fetch Guardian Set" - If you want to try the function before moving forward, create a script inside the `test` directory - - 1. **Create the script file** - - ```bash - touch test/fetchGuardianSet.run.ts - ``` +??? code "View the complete script" + ```ts + import { + Chain, + CircleTransfer, + Network, + Signer, + TransactionId, + TransferState, + Wormhole, + amount, + wormhole, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js'; - 2. **Add the function call** +/* +Notes: +Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains - ```typescript title="test/fetchGuardianSet.run.ts" - import { fetchGuardianSet } from '../src/helpers/vaaHelper'; +AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC +*/ +// -const testFetchGuardianSet = async () => { - const [guardians, guardianSetIndex] = await fetchGuardianSet(); +(async function () { + // Init the Wormhole object, passing in the config for which network + // to use (e.g. Mainnet/Testnet) and what Platforms to support + const wh = await wormhole('Testnet', [evm, solana]); - console.log('Current Guardian Set Index:', guardianSetIndex); - console.log('Guardian Addresses:', guardians); -}; + // Grab chain Contexts + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Solana'); -testFetchGuardianSet(); - ``` + // Get signer from local key but anything that implements + // Signer interface (e.g. wrapper around web wallet) should work + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - 3. **Run the script** + // 6 decimals for USDC (except for BSC, so check decimals before using this) + const amt = amount.units(amount.parse('0.2', 6)); - ```bash - npx tsx test/fetchGuardianSet.run.ts - ``` + // Choose whether or not to have the attestation delivered for you + const automatic = false; - If successful, the output will be: + // If the transfer is requested to be automatic, you can also request that + // during redemption, the receiver gets some amount of native gas transferred to them + // so that they may pay for subsequent transactions + // The amount specified here is denominated in the token being transferred (USDC here) + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; -
-npx tsx test/fetchGuardianSet.run.ts - -Fetching current guardian set -Current Guardian Set Index: 4 -Guardian Addresses: [ - '0x5893b5a76c3f739645648885bdccc06cd70a3cd3', - '0xff6cb952589bde862c25ef4392132fb9d4a42157', - '0x114de8460193bdf3a2fcf81f86a09765f4762fd1', - '0x107a0086b32d7a0977926a205131d8731d39cbeb', - -...] - -
+ await cctpTransfer(wh, source, destination, { + amount: amt, + automatic, + nativeGas, + }); - If an error occurs while fetching the Guardian set, a `500` status error will be logged. +})(); -### Replace Outdated Signatures +async function cctpTransfer( + wh: Wormhole, + src: SignerStuff, + dst: SignerStuff, + req: { + amount: bigint; + automatic: boolean; + nativeGas?: bigint; + } +) { -With the full VAA, Guardian signatures, and the latest Guardian set, we can now update outdated signatures while maintaining the required signature count. + const xfer = await wh.circleTransfer( + // Amount as bigint (base units) + req.amount, + // Sender chain/address + src.address, + // Receiver chain/address + dst.address, + // Automatic delivery boolean + req.automatic, + // Payload to be sent with the transfer + undefined, + // If automatic, native gas can be requested to be sent to the receiver + req.nativeGas + ); -1. **Create the `replaceSignatures()` function** - open `src/helpers/vaaHelper.ts` and add the function header. To catch and handle errors properly, all logic will be wrapped inside a `try` block + // Note, if the transfer is requested to be Automatic, a fee for performing the relay + // will be present in the quote. The fee comes out of the amount requested to be sent. + // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. + // The same applies for native gas dropoff + const quote = await CircleTransfer.quoteTransfer( + src.chain, + dst.chain, + xfer.transfer + ); + console.log('Quote', quote); - ```typescript title="src/helpers/vaaHelper.ts" - vaa: string | Uint8Array, - observations: { guardianAddr: string; signature: string }[], - currentGuardians: string[], - guardianSetIndex: number -) { - console.log('Replacing Signatures...'); + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(src.signer); + console.log(`Started Transfer: `, srcTxids); - try { - // Add logic in the following steps here - console.error('Unexpected error in replaceSignatures:', error); + if (req.automatic) { + const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); + console.log(`Finished relay: `, relayStatus); + return; } -} - ``` - - **`vaa`** - original VAA bytes - - **`observations`** - observed signatures from the network - - **`currentGuardians`** - latest Guardian set - - **`guardianSetIndex`** - current Guardian set index + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(60_000); + console.log(`Got Attestation: `, attestIds); -2. **Validate input data** - ensure all required parameters are present before proceeding. If any required input is missing, the function throws an error to prevent execution with incomplete data. The Guardian set should never be empty; if it is, this likely indicates an error in fetching the Guardian set in a previous step + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(dst.signer); + console.log(`Completed Transfer: `, dstTxids); +} - ```typescript - if (currentGuardians.length === 0) - throw new Error('Guardian set is empty.'); - if (observations.length === 0) throw new Error('No observations provided.'); - ``` +export async function completeTransfer( + wh: Wormhole, + txid: TransactionId, + signer: Signer +): Promise { -3. **Filter valid signatures** - remove signatures from inactive Guardians, keeping only valid ones. If there aren't enough valid signatures to replace the outdated ones, execution is halted to prevent an incomplete or invalid VAA + const xfer = await CircleTransfer.from(wh, txid); - ```typescript - currentGuardians.includes(sig.guardianAddr) - ); + const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); + console.log('Got attestation: ', attestIds); - if (validSigs.length === 0) - throw new Error('No valid signatures found. Cannot proceed.'); + const dstTxIds = await xfer.completeTransfer(signer); + console.log('Completed transfer: ', dstTxIds); +} + ``` -4. **Convert valid signatures** - ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components +### Recovering Transfers - ```typescript - .map((sig) => { - try { - const sigBuffer = Buffer.from(sig.signature, 'base64'); - // If it's 130 bytes, it's hex-encoded and needs conversion - const sigBuffer1 = - sigBuffer.length === 130 - ? Buffer.from(sigBuffer.toString(), 'hex') - : sigBuffer; +It may be necessary to recover an abandoned transfer before it is completed. To do this, instantiate the `Transfer` class with the `from` static method and pass one of several types of identifiers. A `TransactionId` or `WormholeMessageId` may be used to recover the transfer. - const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); - const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); - const vRaw = sigBuffer1[64]; - const v = vRaw < 27 ? vRaw : vRaw - 27; +```ts +const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); + console.log('Got attestation: ', attestIds); - return { - guardianIndex: currentGuardians.indexOf(sig.guardianAddr), - signature: new Signature(r, s, v), - }; - } catch (error) { - console.error( - `Failed to process signature for guardian: ${sig.guardianAddr}`, - error - ); - return null; - } - }) - .filter( - (sig): sig is { guardianIndex: number; signature: Signature } => - sig !== null - ); // Remove null values - ``` + const dstTxIds = await xfer.completeTransfer(signer); + console.log('Completed transfer: ', dstTxIds); +``` -5. **Deserialize the VAA** - convert the raw VAA data into a structured format for further processing +??? code "View the complete script" + ```ts hl_lines="130" + import { + Chain, + CircleTransfer, + Network, + Signer, + TransactionId, + TransferState, + Wormhole, + amount, + wormhole, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js'; - ```typescript - try { - parsedVaa = deserialize('Uint8Array', vaa); - } catch (error) { - throw new Error(`Error deserializing VAA: ${error}`); - } - ``` +/* +Notes: +Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains -6. **Identify outdated signatures** - compare the current VAA signatures with the newly formatted ones to detect which signatures belong to outdated Guardians. Remove these outdated signatures to ensure only valid ones remain +AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC +*/ +// - ```typescript - .filter( - (vaaSig) => - !formattedSigs.some( - (sig) => sig.guardianIndex === vaaSig.guardianIndex - ) - ) - .map((sig) => sig.guardianIndex); +(async function () { + // Init the Wormhole object, passing in the config for which network + // to use (e.g. Mainnet/Testnet) and what Platforms to support + const wh = await wormhole('Testnet', [evm, solana]); - console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); + // Grab chain Contexts + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Solana'); - let updatedSignatures = parsedVaa.signatures.filter( - (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) - ); - ``` + // Get signer from local key but anything that implements + // Signer interface (e.g. wrapper around web wallet) should work + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -7. **Replace outdated signatures** - substitute outdated signatures with valid ones while maintaining the correct number of signatures. If there aren’t enough valid replacements, execution stops + // 6 decimals for USDC (except for BSC, so check decimals before using this) + const amt = amount.units(amount.parse('0.2', 6)); - ```typescript - (sig) => - !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) - ); + // Choose whether or not to have the attestation delivered for you + const automatic = false; + + // If the transfer is requested to be automatic, you can also request that + // during redemption, the receiver gets some amount of native gas transferred to them + // so that they may pay for subsequent transactions + // The amount specified here is denominated in the token being transferred (USDC here) + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + await cctpTransfer(wh, source, destination, { + amount: amt, + automatic, + nativeGas, + }); - // Check if we have enough valid signatures to replace outdated ones** - if (outdatedGuardianIndexes.length > validReplacements.length) { - console.warn( - `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` - ); - return; - } +})(); - updatedSignatures = [ - ...updatedSignatures, - ...validReplacements.slice(0, outdatedGuardianIndexes.length), - ]; +async function cctpTransfer( + wh: Wormhole, + src: SignerStuff, + dst: SignerStuff, + req: { + amount: bigint; + automatic: boolean; + nativeGas?: bigint; + } +) { - updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); - ``` + const xfer = await wh.circleTransfer( + // Amount as bigint (base units) + req.amount, + // Sender chain/address + src.address, + // Receiver chain/address + dst.address, + // Automatic delivery boolean + req.automatic, + // Payload to be sent with the transfer + undefined, + // If automatic, native gas can be requested to be sent to the receiver + req.nativeGas + ); -8. **Serialize the updated VAA** - reconstruct the VAA with the updated signatures and convert it into a format suitable for submission + // Note, if the transfer is requested to be Automatic, a fee for performing the relay + // will be present in the quote. The fee comes out of the amount requested to be sent. + // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee. + // The same applies for native gas dropoff + const quote = await CircleTransfer.quoteTransfer( + src.chain, + dst.chain, + xfer.transfer + ); + console.log('Quote', quote); - ```typescript - ...parsedVaa, - guardianSet: guardianSetIndex, - signatures: updatedSignatures, - }; + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(src.signer); + console.log(`Started Transfer: `, srcTxids); - let patchedVaa: Uint8Array; - try { - patchedVaa = serialize(updatedVaa); - } catch (error) { - throw new Error(`Error serializing updated VAA: ${error}`); - } - ``` + if (req.automatic) { + const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!); + console.log(`Finished relay: `, relayStatus); + return; + } -9. **Send the updated VAA for verification and handle errors** - submit the updated VAA to an Ethereum RPC node for validation, ensuring it can be proposed for Guardian approval. If an error occurs during submission or signature replacement, log the issue and prevent further execution + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(60_000); + console.log(`Got Attestation: `, attestIds); - ```typescript - if (!(patchedVaa instanceof Uint8Array)) - throw new Error('Patched VAA is not a Uint8Array!'); + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(dst.signer); + console.log(`Completed Transfer: `, dstTxids); +} - const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; +export async function completeTransfer( + wh: Wormhole, + txid: TransactionId, + signer: Signer +): Promise { - console.log('Sending updated VAA to RPC...'); + const xfer = await CircleTransfer.from(wh, txid); - const result = await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), - }, - 'latest', - ], - }); + const attestIds = await xfer.fetchAttestation(60 * 60 * 1000); + console.log('Got attestation: ', attestIds); - const verificationResult = result.data.result; - console.log('Updated VAA (hex):', vaaHex); - return verificationResult; - } catch (error) { - throw new Error(`Error sending updated VAA to RPC: ${error}`); - } + const dstTxIds = await xfer.completeTransfer(signer); + console.log('Completed transfer: ', dstTxIds); +} + ``` -???- code "Complete Function" - ```typescript - vaa: string | Uint8Array, - observations: { guardianAddr: string; signature: string }[], - currentGuardians: string[], - guardianSetIndex: number -) { - console.log('Replacing Signatures...'); +## Routes - try { - if (!vaa) throw new Error('VAA is undefined or empty.'); - if (currentGuardians.length === 0) - throw new Error('Guardian set is empty.'); - if (observations.length === 0) throw new Error('No observations provided.'); +While a specific `WormholeTransfer`, such as `TokenTransfer` or `CCTPTransfer`, may be used, the developer must know exactly which transfer type to use for a given request. - const validSigs = observations.filter((sig) => - currentGuardians.includes(sig.guardianAddr) - ); +To provide a more flexible and generic interface, the `Wormhole` class provides a method to produce a `RouteResolver` that can be configured with a set of possible routes to be supported. - if (validSigs.length === 0) - throw new Error('No valid signatures found. Cannot proceed.'); +The following section demonstrates setting up and validating a token transfer using Wormhole's routing system. - const formattedSigs = validSigs - .map((sig) => { - try { - const sigBuffer = Buffer.from(sig.signature, 'base64'); - // If it's 130 bytes, it's hex-encoded and needs conversion - const sigBuffer1 = - sigBuffer.length === 130 - ? Buffer.from(sigBuffer.toString(), 'hex') - : sigBuffer; +```ts +const resolver = wh.resolver([ + routes.TokenBridgeRoute, // manual token bridge + routes.AutomaticTokenBridgeRoute, // automatic token bridge + routes.CCTPRoute, // manual CCTP + routes.AutomaticCCTPRoute, // automatic CCTP + routes.AutomaticPorticoRoute, // Native eth transfers + ]); +``` - const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); - const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); - const vRaw = sigBuffer1[64]; - const v = vRaw < 27 ? vRaw : vRaw - 27; +Once created, the resolver can be used to provide a list of input and possible output tokens. - return { - guardianIndex: currentGuardians.indexOf(sig.guardianAddr), - signature: new Signature(r, s, v), - }; - } catch (error) { - console.error( - `Failed to process signature for guardian: ${sig.guardianAddr}`, - error - ); - return null; - } - }) - .filter( - (sig): sig is { guardianIndex: number; signature: Signature } => - sig !== null - ); // Remove null values +```ts +const srcTokens = await resolver.supportedSourceTokens(sendChain); + console.log( + 'Allowed source tokens: ', + srcTokens.map((t) => canonicalAddress(t)) + ); - let parsedVaa: VAA<'Uint8Array'>; - try { - parsedVaa = deserialize('Uint8Array', vaa); - } catch (error) { - throw new Error(`Error deserializing VAA: ${error}`); - } + const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); - const outdatedGuardianIndexes = parsedVaa.signatures - .filter( - (vaaSig) => - !formattedSigs.some( - (sig) => sig.guardianIndex === vaaSig.guardianIndex - ) - ) - .map((sig) => sig.guardianIndex); + // Given the send token, what can we possibly get on the destination chain? + const destTokens = await resolver.supportedDestinationTokens( + sendToken, + sendChain, + destChain + ); + console.log( + 'For the given source token and routes configured, the following tokens may be receivable: ', + destTokens.map((t) => canonicalAddress(t)) + ); + // Grab the first one for the example + const destinationToken = destTokens[0]!; +``` - console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); +Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfill the request. Creating a transfer request fetches the token details since all routes will need to know about the tokens. - let updatedSignatures = parsedVaa.signatures.filter( - (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) - ); +```ts +// Since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source: sendToken, + destination: destinationToken, + }); - const validReplacements = formattedSigs.filter( - (sig) => - !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) - ); + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + console.log( + 'For the transfer parameters, we found these routes: ', + foundRoutes + ); +``` - // Check if we have enough valid signatures to replace outdated ones** - if (outdatedGuardianIndexes.length > validReplacements.length) { - console.warn( - `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` - ); - return; - } +Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - updatedSignatures = [ - ...updatedSignatures, - ...validReplacements.slice(0, outdatedGuardianIndexes.length), - ]; +After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. - updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); +After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. - const updatedVaa: VAA<'Uint8Array'> = { - ...parsedVaa, - guardianSet: guardianSetIndex, - signatures: updatedSignatures, - }; +```ts +'This route offers the following default options', + bestRoute.getDefaultOptions() + ); - let patchedVaa: Uint8Array; - try { - patchedVaa = serialize(updatedVaa); - } catch (error) { - throw new Error(`Error serializing updated VAA: ${error}`); - } + // Specify the amount as a decimal string + const amt = '0.001'; + // Create the transfer params for this request + const transferParams = { amount: amt, options: { nativeGas: 0 } }; - try { - if (!(patchedVaa instanceof Uint8Array)) - throw new Error('Patched VAA is not a Uint8Array!'); + // Validate the transfer params passed, this returns a new type of ValidatedTransferParams + // which (believe it or not) is a validated version of the input params + // This new var must be passed to the next step, quote + const validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) throw validated.error; + console.log('Validated parameters: ', validated.params); - const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; + // Get a quote for the transfer, this too returns a new type that must + // be passed to the next step, execute (if you like the quote) + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) throw quote.error; + console.log('Best route quote: ', quote); +``` - console.log('Sending updated VAA to RPC...'); +Finally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`. - const result = await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), - }, - 'latest', - ], - }); +```ts +tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); +``` - const verificationResult = result.data.result; - console.log('Updated VAA (hex):', vaaHex); - return verificationResult; - } catch (error) { - throw new Error(`Error sending updated VAA to RPC: ${error}`); - } - } catch (error) { - console.error('Unexpected error in replaceSignatures:', error); - } -} - ``` +??? code "View the complete script" -## Create Script to Replace Outdated VAA Signatures + ```ts + import { + Wormhole, + canonicalAddress, + routes, + wormhole, +} from '@wormhole-foundation/sdk'; -Now that we have all the necessary helper functions, we will create a script to automate replacing outdated VAA signatures. This script will retrieve a transaction’s VAA sequentially, check its validity, fetch the latest Guardian set, and update its signatures. By the end, it will output a correctly signed VAA that can be proposed for Guardian approval. +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/index.js'; -1. **Open the file** - inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs +(async function () { + // Setup + const wh = await wormhole('Testnet', [evm, solana]); - ```typescript title="src/scripts/replaceSignatures.ts" - fetchVaaId, - fetchVaa, - checkVaaValidity, - fetchObservations, - fetchGuardianSet, - replaceSignatures, -} from '../helpers/vaaHelper'; -import { TXS } from '../config/constants'; - ``` + // Get chain contexts + const sendChain = wh.getChain('Avalanche'); + const destChain = wh.getChain('Solana'); -2. **Define the main execution function** - add the following function inside `src/scripts/replaceSignatures.ts` to process each transaction in `TXS`, going step by step through the signature replacement process + // Get signers from local config + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); - ```typescript - try { - for (const tx of TXS) { - console.log(`\nProcessing TX: ${tx}\n`); + // Create new resolver, passing the set of routes to consider + const resolver = wh.resolver([ + routes.TokenBridgeRoute, // manual token bridge + routes.AutomaticTokenBridgeRoute, // automatic token bridge + routes.CCTPRoute, // manual CCTP + routes.AutomaticCCTPRoute, // automatic CCTP + routes.AutomaticPorticoRoute, // Native eth transfers + ]); - // 1. Fetch Transaction VAA IDs: - const vaaIds = await fetchVaaId([tx]); - if (!vaaIds.length) continue; + // What tokens are available on the source chain? + const srcTokens = await resolver.supportedSourceTokens(sendChain); + console.log( + 'Allowed source tokens: ', + srcTokens.map((t) => canonicalAddress(t)) + ); - // 2. Fetch VAA Data: - const vaaData = await fetchVaa(vaaIds); - if (!vaaData.length) continue; + const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); - const vaaBytes = vaaData[0].vaaBytes; - if (!vaaBytes) continue; + // Given the send token, what can we possibly get on the destination chain? + const destTokens = await resolver.supportedDestinationTokens( + sendToken, + sendChain, + destChain + ); + console.log( + 'For the given source token and routes configured, the following tokens may be receivable: ', + destTokens.map((t) => canonicalAddress(t)) + ); + // Grab the first one for the example + const destinationToken = destTokens[0]!; - // 3. Check VAA Validity: - const { valid } = await checkVaaValidity(vaaBytes); - if (valid) continue; + // Creating a transfer request fetches token details + // Since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source: sendToken, + destination: destinationToken, + }); - // 4. Fetch Observations (VAA signatures): - const observations = await fetchObservations(vaaIds[0]); + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + console.log( + 'For the transfer parameters, we found these routes: ', + foundRoutes + ); - // 5. Fetch Current Guardian Set: - const [currentGuardians, guardianSetIndex] = await fetchGuardianSet(); + const bestRoute = foundRoutes[0]!; + console.log('Selected: ', bestRoute); - // 6. Replace Signatures: - const response = await replaceSignatures( - Buffer.from(vaaBytes, 'base64'), - observations, - currentGuardians, - guardianSetIndex - ); + console.log( + 'This route offers the following default options', + bestRoute.getDefaultOptions() + ); - if (!response) continue; - } - } catch (error) { - console.error('❌ Error in execution:', error); - process.exit(1); - } -} - ``` + // Specify the amount as a decimal string + const amt = '0.001'; + // Create the transfer params for this request + const transferParams = { amount: amt, options: { nativeGas: 0 } }; -3. **Make the script executable** - ensure it runs when executed + // Validate the transfer params passed, this returns a new type of ValidatedTransferParams + // which (believe it or not) is a validated version of the input params + // This new var must be passed to the next step, quote + const validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) throw validated.error; + console.log('Validated parameters: ', validated.params); - ```typescript - - ``` + // Get a quote for the transfer, this too returns a new type that must + // be passed to the next step, execute (if you like the quote) + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) throw quote.error; + console.log('Best route quote: ', quote); - To run the script, use the following command: + // If you're sure you want to do this, set this to true + const imSure = false; + if (imSure) { + // Now the transfer may be initiated + // A receipt will be returned, guess what you gotta do with that? + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); - ```bash - npx tsx src/scripts/replaceSignatures.ts + // Kick off a wait log, if there is an opportunity to complete, this function will do it + // See the implementation for how this works + await routes.checkAndCompleteTransfer(bestRoute, receipt, receiver.signer); + } else { + console.log('Not initiating transfer (set `imSure` to true to do so)'); + } +})(); ``` -
-npx tsx src/scripts/replaceSignatures.ts - -Processing TX: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -❌ VAA Valid: false, Reason: VM signature invalid -Fetching observations -Fetching current guardian set -Replacing Signatures... -Outdated Guardian Indexes: [ 0 ] -Sending updated VAA to RPC... -Updated VAA (hex): 0x01000000040d010019447b72d51e33923a3d6b28496ccd3722d5f1e33e2... - -
+See the `router.ts` example in the [examples directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/examples){target=\_blank} for a full working example. -The script logs each step, skipping valid VAAs, replacing outdated signatures for invalid VAAs, and logging any errors. It then completes with a valid VAA ready for submission. +### Routes as Plugins -## Resources +Routes can be imported from any npm package that exports them and configured with the resolver. Custom routes must extend [`Route`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L21-L64){target=\_blank} and implement [`StaticRouteMethods`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L101){target=\_blank}. -You can explore the complete project and find all necessary scripts and configurations in Wormhole's [demo GitHub repository](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank}. +```ts +import { Network, routes } from '@wormhole-foundation/sdk-connect'; -The demo repository includes a bonus script to check the VAA redemption status on Ethereum and Solana, allowing you to verify whether a transaction has already been redeemed on the destination chain. +export class CustomRoute + extends routes.Route + implements routes.StaticRouteMethods +{ + static meta = { + name: 'CustomRoute', + }; + // implementation... +} + +``` -## Conclusion +A noteworthy example of a route exported from a separate npm package is Wormhole Native Token Transfers (NTT). See the [`NttAutomaticRoute`](https://github.com/wormhole-foundation/native-token-transfers/blob/66f8e414223a77f5c736541db0a7a85396cab71c/sdk/route/src/automatic.ts#L48){target=\_blank} route implementation. -You've successfully built a script to fetch, validate, and replace outdated signatures in VAAs using Wormholescan and the Wormhole SDK. +## See Also -It's important to note that this tutorial does not update VAAs in the Wormhole network. Before redeeming the VAA, you must propose it for Guardian approval to finalize the process. +The TSdoc is available [on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank}. --- END CONTENT --- diff --git a/llms.txt b/llms.txt index 011e0e552..252b784f5 100644 --- a/llms.txt +++ b/llms.txt @@ -4,116 +4,120 @@ ## Docs +- [Core Messaging Layer Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/core-messaging/index.md): Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. +- [Getting Started with MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov/index.md): Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. +- [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md): Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. +- [Use Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md): Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. +- [Use Cases](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md): Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +- [Wormhole CLI](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md): Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. +- [Local Dev Environment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md): Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. +- [Toolkit FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md): FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. +- [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. +- [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. +- [Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md): Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. +- [Native Token Transfers Installation](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md): Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. +- [Native Token Transfers Post Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md): Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +- [Native Token Transfers (NTT)](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/index.md): This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. +- [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +- [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md): Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. +- [Glossary](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md): Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +- [MultiGov Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md): Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. +- [Circle's CCTP Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md): Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. +- [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/index.md): This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. +- [Native Token Transfers - Deployment Models](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md): Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. +- [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md): Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. +- [Wormhole Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md): Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. +- [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md): No description available. +- [Complete USDC Transfer Flow](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +- [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +- [Configure Your Connect Widget v0](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md): Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. +- [Connect Data Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md): Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +- [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. +- [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md): No description available. +- [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md): No description available. +- [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. +- [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md): No description available. - [Get Started with Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md): This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -- [Core Messaging Layer Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/core-messaging/index.md): Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. - [Wormhole-Deployed Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md): Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -- [Build with Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/index.md): Learn how to start building multichain solutions on Wormhole, with tips to get started, an overview of the toolkit, and an introduction to the protocols. -- [Run Infrastructure Services](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/index.md): Follow the guides in this section to learn how to run off-chain infrastructure services, such as running a spy or a customized relayer. -- [Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/index.md): Learn how to develop your own custom off-chain relaying service, giving you greater control and flexibility than using Wormhole-deployed relayers. -- [Run a Relayer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/relayers/run-relayer.md): Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -- [Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/infrastructure/spy/index.md): Discover everything you need to about the Wormhole Spy, a daemon that watches the Guardian Network and subscribe to signed messages. -- [Run a Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md): Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md): No description available. +- [Create Cross-Chain Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md): Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. +- [Cross-Chain Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md): Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. +- [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. +- [MultiGov Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md): Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. +- [MultiGov FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md): No description available. - [Deploy MultiGov on EVM Chains](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md): Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [MultiGov Deployment to Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md): Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. -- [MultiGov Technical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -- [Getting Started with MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/multigov/index.md): Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. - [Upgrading MultiGov on EVM](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md): Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. - [Upgrading MultiGov on Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md): Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. -- [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. -- [Wormhole Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/index.md): Wormhole Queries offers on-demand access to Guardian-attested on-chain data via a simple REST endpoint to initiate an off-chain request via a proxy. -- [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/overview.md): Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -- [Use Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/queries/use-queries.md): Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -- [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. -- [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. -- [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. -- [Reference](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/index.md): Find essential reference information for development, including canonical contract addresses, Wormhole chain IDs, and Wormhole finality levels for Guardians. -- [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -- [Start Building](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/index.md): This section has all you need to start developing with Wormhole, including a guide to supported networks, tool sets, and code examples. -- [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. -- [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. -- [Use Cases](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/start-building/use-cases.md): Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -- [Wormhole CLI](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/cli.md): Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. -- [Local Dev Environment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/dev-env.md): Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. -- [Toolkit FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/faqs.md): FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. -- [Wormhole Tooling](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/index.md): This page lists key dev tools, including the WormholeScan Explorer, Wormhole CLI, Wormhole SDKs, and APIs for querying network data. -- [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. -- [Wormhole SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/toolkit/typescript-sdk/index.md): The Wormhole SDK provides tools for cross-chain communication, token bridges, and more, enabling developers to integrate with multiple blockchain environments. -- [Building Protocols and Payloads](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md): Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. -- [Data Layouts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md): Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. -- [VAAs and Protocols](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md): Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. -- [Wormhole TS SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md): Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. -- [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/cctp.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -- [Configure Your Connect Widget v0](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md): Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. -- [Connect Data Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md): Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. -- [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. -- [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/configuration/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. -- [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -- [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. -- [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -- [Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/connect/overview.md): Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -- [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -- [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -- [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/index.md): This section guides you through using Wormhole products to securely and efficiently transfer assets and messages across multiple blockchains. -- [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/overview.md): No description available. +- [MultiGov Guides](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md): Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. +- [Native Token Transfers Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md): Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +- [Native Token Transfers Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md): Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. - [Native Token Transfers Access Control](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md): Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. -- [Native Token Transfers (NTT) - Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/configuration/index.md): This section contains information on configuring Native Token Transfers (NTT), including guidance on setting Owner and Pauser access control roles and management of rate-limiting. - [Native Token Transfers Rate Limiting](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md): Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. +- [Native Token Transfers FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md): Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md): No description available. - [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -- [Native Token Transfers (NTT) - Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/index.md): This section provides information on installing Wormhole's Native Token Transfer framework, deployment to EVM and Solana, and post deployment NTT maintenance. -- [Native Token Transfers Installation](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/installation.md): Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -- [Native Token Transfers Post Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/deployment-process/post-deployment.md): Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md): No description available. +- [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. - [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. -- [Native Token Transfers FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md): Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -- [Native Token Transfers (NTT)](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/index.md): This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -- [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/native-token-transfers/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +- [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md): No description available. +- [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/construct-a-query.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/mock-a-query.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/query-request.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md): No description available. +- [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. +- [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. +- [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. +- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +- [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. +- [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +- [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. - [Wormhole Settlement FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md): Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. -- [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/settlement/index.md): Start building with Wormhole Settlement; integrate with the Liquidity Layer and set up Solvers to enable seamless cross-chain asset transfers. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md): No description available. - [Wormhole Settlement Liquidity Layer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md): Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. - [Wormhole Settlement Solver](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md): Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -- [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/build/transfers/token-bridge.md): Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -- [Glossary](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/glossary.md): Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -- [MultiGov Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md): Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. -- [MultiGov Theoretical FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -- [Learn about MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/index.md): Explore the MultiGov documentation for a comprehensive guide covering architecture, deployment, upgrading, integration, and FAQs. -- [MultiGov Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/governance/overview.md): Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -- [Learn about Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/index.md): Learn the basics of Wormhole, covering its architecture, messaging protocols, and how it enables multichain communication and asset transfers. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md): No description available. +- [Wormhole Settlements](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/tutorials/.settlement-routes.md): Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): No description available. +- [Token Bridge FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md): Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md): No description available. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md): No description available. +- [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. +- [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains - [Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md): Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +- [Run a Relayer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-relayer.md): Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +- [Run a Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure-guides/run-spy.md): Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. - [Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md): Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. - [Guardians](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/guardians.md): Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -- [Infrastructure Components](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/index.md): Explore Wormhole's infrastructure, including the key components that enable secure multichain communication and asset transfers across blockchain networks. - [Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/relayer.md): Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - [Spy](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/spy.md): Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - [VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md): Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. - [Introduction to Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md): Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. - [Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md): Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -- [Circle's CCTP Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/cctp.md): Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -- [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/index.md): This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -- [Native Token Transfers Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md): Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. -- [Native Token Transfers - Deployment Models](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/deployment.md): Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -- [A Quick Look at Native Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/index.md): This section covers Wormhole's Native Token Transfers (NTT), an open source, flexible, and composable framework for transferring tokens across blockchains. -- [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/overview.md): Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -- [Native Token Transfers Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/native-token-transfers/security.md): Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -- [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. -- [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/index.md): Learn about Wormhole Settlement, an intent-based solution enabling fast and efficient asset transfers across Ethereum, Solana, Sui, and more. -- [Wormhole Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/settlement/overview.md): Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -- [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -- [Wormhole Connect Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/connect/index.md): Enable cross-chain connectivity with Wormhole Connect. Learn integration and simplify user experiences across multiple blockchains. -- [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -- [Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/index.md): Discover product-specific Wormhole tutorials. Learn setup, integration, and advanced features to develop cross-chain apps confidently. -- [Multichain Assets Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multichain-assets/index.md): Explore comprehensive, step-by-step tutorials on how to register, manage, and work with multichain assets within the Wormhole ecosystem. -- [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. -- [Step-by-Step MultiGov Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/multigov/index.md): Access step-by-step guides for executing cross-chain governance actions, including treasury management proposals with MultiGov and Wormhole. -- [MultiGov Guides](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md): Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. -- [Wormhole Settlement](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.index.md): Follow step-by-step tutorials to integrate Wormhole Settlement Routes using the SDK for seamless cross-chain swaps and efficient asset transfers. -- [Wormhole Settlements](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/settlement/.settlement-routes.md): Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. -- [Create Cross-Chain Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md): Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. -- [Cross-Chain Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md): Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. -- [Solidity SDK Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/solidity-sdk/index.md): Master cross-chain smart contracts with Wormhole's Solidity SDK. Learn messaging, token transfers, and secure, scalable dApp deployments across blockchains. -- [Wormhole SDK Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/typescript-sdk/index.md): Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. -- [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [Transfer USDC via CCTP and Wormhole SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. -- [Wormholescan API Tutorials](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tutorials/wormholescan/index.md): Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. -- [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. \ No newline at end of file +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md): No description available. +- [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. +- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md): No description available. +- [Building Protocols and Payloads](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md): Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. +- [Data Layouts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md): Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. +- [VAAs and Protocols](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md): Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. +- [Wormhole TS SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/sdk-reference.md): Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC. \ No newline at end of file From 990adbfe9750c8fa51264b647c33c2d345bb45cc Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Wed, 30 Apr 2025 11:57:55 -0400 Subject: [PATCH 04/55] add support for tool selector --- .pages | 2 +- js/tool-selector.js | 13 +++++++++++++ tools/.pages | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 js/tool-selector.js diff --git a/.pages b/.pages index 11733efcd..5d48d4074 100644 --- a/.pages +++ b/.pages @@ -2,4 +2,4 @@ nav: - products - protocol - 'AI Resources': ai-resources.md -# - tools \ No newline at end of file +- tools \ No newline at end of file diff --git a/js/tool-selector.js b/js/tool-selector.js new file mode 100644 index 000000000..8c8844dc1 --- /dev/null +++ b/js/tool-selector.js @@ -0,0 +1,13 @@ +document.addEventListener('DOMContentLoaded', () => { + const selectWrapper = document.querySelector('.select-wrapper'); + const openArrow = document.querySelector('.selector-open'); + const closedArrow = document.querySelector('.selector-closed'); + + // Add event listeners + selectWrapper.addEventListener('click', () => { + console.log('hello'); + selectWrapper.classList.toggle('active'); + openArrow.classList.toggle('active'); + closedArrow.classList.toggle('active'); + }); +}); diff --git a/tools/.pages b/tools/.pages index c83c147f8..35c556581 100644 --- a/tools/.pages +++ b/tools/.pages @@ -1,4 +1,4 @@ -title: Developer Tooling +title: Developer Tools nav: - typescript-sdk - solidity-sdk From 99c55cc74d471f0b87ea0e8e2c4b97d28047db17 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Thu, 1 May 2025 11:50:03 -0400 Subject: [PATCH 05/55] add logic so the dropdown closes when a user clicks anywhere else on the page --- js/tool-selector.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/js/tool-selector.js b/js/tool-selector.js index 8c8844dc1..ee918eac1 100644 --- a/js/tool-selector.js +++ b/js/tool-selector.js @@ -1,13 +1,22 @@ document.addEventListener('DOMContentLoaded', () => { const selectWrapper = document.querySelector('.select-wrapper'); const openArrow = document.querySelector('.selector-open'); - const closedArrow = document.querySelector('.selector-closed'); + const closedArrow = document.querySelector('.selector-closed');; // Add event listeners - selectWrapper.addEventListener('click', () => { - console.log('hello'); + selectWrapper.addEventListener('click', (event) => { selectWrapper.classList.toggle('active'); openArrow.classList.toggle('active'); closedArrow.classList.toggle('active'); + event.stopPropagation(); // prevent it from triggering document click + }); + + // Close on outside click + document.addEventListener('click', (event) => { + if (!selectWrapper.contains(event.target)) { + selectWrapper.classList.remove('active'); + openArrow.classList.remove('active'); + closedArrow.classList.add('active'); + } }); }); From 66cbbdc6e479585dada70bdbf614771ff9066294 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Mon, 5 May 2025 16:24:43 -0400 Subject: [PATCH 06/55] update messaging tutorial .pages file --- products/messaging/tutorials/.pages | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/products/messaging/tutorials/.pages b/products/messaging/tutorials/.pages index 5a1cfbbdf..e4e12fdcb 100644 --- a/products/messaging/tutorials/.pages +++ b/products/messaging/tutorials/.pages @@ -1,4 +1,5 @@ title: Tutorials nav: -- 'Overview': overview.md -- 'Get Started': get-started.md \ No newline at end of file +- 'Create Messaging Contracts': cross-chain-contracts.md +- 'Create Token Transfer Contracts': cross-chain-token-contracts.md +- 'Replace Outdated Signatures in VAAs': replace-signatures.md \ No newline at end of file From 209f9707becbd943a17e14c23c9331f31c36a2d9 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Tue, 6 May 2025 01:43:07 -0400 Subject: [PATCH 07/55] move ai resources to a directory --- .pages | 2 +- ai-resources/.pages | 3 +++ ai-resources.md => ai-resources/ai-resources.md | 0 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 ai-resources/.pages rename ai-resources.md => ai-resources/ai-resources.md (100%) diff --git a/.pages b/.pages index 5d48d4074..382023beb 100644 --- a/.pages +++ b/.pages @@ -1,5 +1,5 @@ nav: - products - protocol -- 'AI Resources': ai-resources.md +- ai-resources - tools \ No newline at end of file diff --git a/ai-resources/.pages b/ai-resources/.pages new file mode 100644 index 000000000..32fe674c8 --- /dev/null +++ b/ai-resources/.pages @@ -0,0 +1,3 @@ +title: AI Resources +nav: +- 'Download LLM Files': ai-resources.md \ No newline at end of file diff --git a/ai-resources.md b/ai-resources/ai-resources.md similarity index 100% rename from ai-resources.md rename to ai-resources/ai-resources.md From ac88301c26917a218b4c4e30a6b37bbb69517b84 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Tue, 6 May 2025 14:36:41 +0200 Subject: [PATCH 08/55] Queries - Get Started page (#377) * initial draft for queries * initial queries draft * grammarly check * update file name * add metadata * add full script * short description to steps * rename title * update script * update based on feedback * create snippet for queries * move code to snippet * rename sections * Update products/queries/get-started.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update snippets path * update title * update intro * link to queries package * context of what Query Proxy is * update style * lowercase constants * update expected output * update links * update titles * Apply suggestions from code review Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update page based on feedback --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> --- .../products/queries/get-started/snippet-1.ts | 60 ++++++++++++++ .../queries/get-started/snippet-2.html | 13 +++ products/queries/get-started.md | 83 ++++++++++++++++++- 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/products/queries/get-started/snippet-1.ts create mode 100644 .snippets/code/products/queries/get-started/snippet-2.html diff --git a/.snippets/code/products/queries/get-started/snippet-1.ts b/.snippets/code/products/queries/get-started/snippet-1.ts new file mode 100644 index 000000000..ef24d019b --- /dev/null +++ b/.snippets/code/products/queries/get-started/snippet-1.ts @@ -0,0 +1,60 @@ +// Import the SDK types and helpers for making the query +import { + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; +import * as eth from 'web3'; + +// Define the endpoint and query parameters +const query_url = 'https://testnet.query.wormhole.com/v1/query'; +const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public'; +const chain_id = 10002; // Sepolia (Wormhole chain ID) +const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract +const data = '0x06fdde03'; // function selector for `name()` + +// Load your API key from environment variables +const apiKey = process.env.API_KEY; +if (!apiKey) throw new Error('API_KEY is not set in your environment'); + +(async () => { + // Fetch the latest block number (required to anchor the query) + const latestBlock = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + + // Build the query targeting the token contract's name() function + const request = new QueryRequest(1, [ + new PerChainQueryRequest( + chain_id, + new EthCallQueryRequest(latestBlock, [{ to: token, data: data }]) + ), + ]); + const serialized = request.serialize(); + + // Send the query to the Wormhole Query Proxy + const response = await axios.post( + query_url, + { bytes: Buffer.from(serialized).toString('hex') }, + { headers: { 'X-API-Key': apiKey } } + ); + + // Decode the response returned by the Guardian network + const queryResponse = QueryResponse.from(response.data.bytes); + const chainResponse = queryResponse.responses[0] + .response as EthCallQueryResponse; + const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]); + + // Output the results + console.log('\n\nParsed chain response:'); + console.log(chainResponse); + console.log('\nToken name:', name); +})(); diff --git a/.snippets/code/products/queries/get-started/snippet-2.html b/.snippets/code/products/queries/get-started/snippet-2.html new file mode 100644 index 000000000..b25cede17 --- /dev/null +++ b/.snippets/code/products/queries/get-started/snippet-2.html @@ -0,0 +1,13 @@ +
+ API_KEY=123_456_789 npx tsx query.ts + Parsed chain response: + EthCallQueryResponse { + blockNumber: 8193548n, + blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8', + blockTime: 1745595132000000n, + results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000'] + } + + Token name: USDC + +
diff --git a/products/queries/get-started.md b/products/queries/get-started.md index 30404ce4c..6407b0dc8 100644 --- a/products/queries/get-started.md +++ b/products/queries/get-started.md @@ -1 +1,82 @@ -TODO \ No newline at end of file +--- +title: Get Started with Queries +description: Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. +categories: Queries +--- + +# Get Started with Queries + +## Introduction + +[Queries](/docs/products/queries/overview) lets you fetch on-chain data from supported blockchains using `eth_call`-style requests without submitting transactions or paying gas. The Guardian network signs the result, making it verifiable and suitable for use on-chain. + +This guide walks you through requesting an API key, constructing your first query using the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, and decoding the result. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - A basic understanding of JavaScript or TypeScript + - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia) + - A Wormhole Queries API key + +## Request an API Key + +Wormhole Queries is in closed beta, but you can start building today. + +To interact with the system, you will use the Query Proxy. This hosted service receives your query, routes it to the appropriate chain, and returns a signed, verifiable response from the Guardian network. The Query Proxy allows you to fetch on-chain data without infrastructure overhead. + +To request access, join the beta by filling out the [access form](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. Once approved, you will receive an API key via email. + +## Construct a Query and Decode the Response + +Using the Wormhole Query Proxy, you will write a lightweight script to query a token contract's `name()` on Ethereum Sepolia. The response is signed by the Guardian network and locally decoded for use in your application. + +1. Create a new directory for your script and initialize a Node.js project: + + ```bash + mkdir queries + cd queries + npm init -y + ``` + +2. Add the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, [Axios](https://www.npmjs.com/package/axios){target=\_blank}, [Web3](https://www.npmjs.com/package/web3){target=\_blank}, and helper tools: + + ```bash + npm install axios web3 @wormhole-foundation/wormhole-query-sdk + npm install -D tsx typescript + ``` + +3. Add a new `query.ts` script where you will write and run your query logic: + + ```bash + touch query.ts + ``` + +4. Paste the following script into `query.ts` to build and submit a query to the token contract's `name()` function on Ethereum Sepolia, then decode the Guardian-signed response: + + ```typescript + --8<-- "code/products/queries/get-started/snippet-1.ts" + ``` + +5. Use your API key to execute the script: + + ```bash + API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts + ``` + +The expected output should be similar to this: + +--8<-- "code/products/queries/get-started/snippet-2.html" + +## Next Steps + +Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: + + - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM + - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually + - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts + +Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. + From 02370ffb05476c6ec82310bb5c3e70960c7bb9e8 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Tue, 6 May 2025 14:37:59 +0200 Subject: [PATCH 09/55] NTT - Get Started page (#376) * first draft of ntt setup * update left hand menu order * add file context * Apply suggestions from code review Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update based on feedback * grammarly check * update links * Apply suggestions from code review Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Erin Shaben * update metadata title * update description metadata * update metadata description * update intro based on feedback * remove update ntt cli section * convert steps into ordered list * update config file based on feedback * update based on feedback * update based on feedback * Update products/native-token-transfers/get-started.md Co-authored-by: Erin Shaben * update based on feedback * add erc20 token deployment steps --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Erin Shaben --- products/native-token-transfers/.pages | 2 +- .../native-token-transfers/get-started.md | 194 +++++++++++++++++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/products/native-token-transfers/.pages b/products/native-token-transfers/.pages index 69372bf1f..0a3b59977 100644 --- a/products/native-token-transfers/.pages +++ b/products/native-token-transfers/.pages @@ -2,8 +2,8 @@ title: Native Token Transfers nav: - 'Overview': overview.md - 'Get Started': get-started.md -- configuration - guides +- configuration - concepts - 'Troubleshooting': troubleshooting.md - 'FAQs': faqs.md diff --git a/products/native-token-transfers/get-started.md b/products/native-token-transfers/get-started.md index 30404ce4c..2dd0b64f6 100644 --- a/products/native-token-transfers/get-started.md +++ b/products/native-token-transfers/get-started.md @@ -1 +1,193 @@ -TODO \ No newline at end of file +--- +title: Get Started with NTT +description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. +categories: NTT, Transfer +--- + +# Get Started with NTT + +## Introduction + +The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. + +If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. + +## Prerequisites + +Before you begin, make sure you have: + +- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Bun installed](https://bun.sh/){target=\_blank} +- A wallet private key with tokens on supported chains +- ERC-20 or SPL tokens already deployed on the source and destination chains + +## Don’t Have a Token Yet? + +To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. + +???- interface "Deploy an ERC-20 Token on EVM" + Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. + + 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} + + 2. **Clone the repository** – fetch the example contract repository + + ```bash + git clone https://github.com/wormhole-foundation/example-ntt-token.git + cd example-ntt-token + ``` + + 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses + + ```bash + forge create --broadcast \ + --rpc-url INSERT_RPC_URL \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + src/PeerToken.sol:PeerToken \ + --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS + ``` + + 4. **Mint tokens** – send tokens to your address + + ```bash + cast send INSERT_TOKEN_ADDRESS \ + "mint(address,uint256)" \ + INSERT_RECIPIENT_ADDRESS \ + INSERT_AMOUNT_IN_WEI \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + --rpc-url INSERT_RPC_URL + ``` + + !!! note + This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). + + +???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. + + 1. **Generate a Solana key pair** - run the following command to create a new wallet: + + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` + + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: + + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` + + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: + + === "Mainnet" + ```bash + solana config set -um + ``` + + === "Testnet" + ```bash + solana config set -ut + ``` + + === "Devnet" + ```bash + solana config set -ud + ``` + + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: + + ```bash + solana airdrop 2 + solana balance + ``` + + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} + + ```bash + cargo install spl-token-cli + ``` + + 6. **Create a new SPL token** - initialize the token on Solana + + ```bash + spl-token create-token + ``` + + 7. **Create a token account** - generate an account to hold the token + + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` + + 8. **Mint tokens** - send 1000 tokens to the created account + + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` + + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. + +## Install NTT CLI + +The NTT CLI is recommended to deploy and manage your cross-chain token configuration. + +1. Run the installation command in your terminal: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + +2. Verify the NTT CLI is installed: + + ```bash + ntt --version + ``` + +## Initialize a New NTT Project + +1. Once the CLI is installed, scaffold a new project by running: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +2. Initialize a new `deployment.json` file specifying the network: + + === "Mainnet" + ```bash + ntt init Mainnet + ``` + + === "Testnet" + ```bash + ntt init Testnet + ``` + + After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. + + === "Mainnet" + ```json + { + "network": "Mainnet", + "chains": {} + } + ``` + + === "Testnet" + ```json + { + "network": "Testnet", + "chains": {} + } + ``` + +In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. + +## Next Steps + +You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: + +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} From 8c212e0afd0baa66e6af49045ecb2f2cbf633c1c Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 9 May 2025 01:21:27 -0400 Subject: [PATCH 10/55] move tools --- .pages | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pages b/.pages index 382023beb..dd1646162 100644 --- a/.pages +++ b/.pages @@ -1,5 +1,5 @@ nav: - products - protocol -- ai-resources -- tools \ No newline at end of file +- tools +- ai-resources \ No newline at end of file From 7fe8e302cfb54f15154655889bfe844442832dda Mon Sep 17 00:00:00 2001 From: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Date: Tue, 13 May 2025 00:33:09 -0400 Subject: [PATCH 11/55] Connect - Get Started page (#375) * adds draft markdown * updates based on feedback, handles snippet and image * grammarly pass * updates after seeing Martin's awesome draft! * updated to use Sui --> Fuji repo from WH * format snippet with prettier, updates to content per review feedback --- .../connect/configuration/get-started/App.tsx | 30 +++++++ .../get-started/connect-get-started-01.webp | Bin 0 -> 44478 bytes products/connect/get-started.md | 77 +++++++++++++++++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/products/connect/configuration/get-started/App.tsx create mode 100644 images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp diff --git a/.snippets/code/products/connect/configuration/get-started/App.tsx b/.snippets/code/products/connect/configuration/get-started/App.tsx new file mode 100644 index 000000000..4740d2bad --- /dev/null +++ b/.snippets/code/products/connect/configuration/get-started/App.tsx @@ -0,0 +1,30 @@ +import './App.css'; +import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; + +function App() { + const config: WormholeConnectConfig = { + // Define the network + network: 'Testnet', + + // Define the chains + chains: ['Sui', 'Avalanche'], + + // UI configuration + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + // Define the theme + mode: 'dark', + primary: '#78c4b6', + }; + + return ; +} + +export default App; diff --git a/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp b/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp new file mode 100644 index 0000000000000000000000000000000000000000..f6ebe452f7a2c3cd4d86ba3224fa85735db30118 GIT binary patch literal 44478 zcmd?RWpEr@mNhELVn&OZnJktpW@ct)W+sc7S+>w(W@ct)u$Y-u&pkce)A#n(%)IZ5 z_v=NRsL0I7sLH+fT5GR;R3!y*5s`*+ARtv?0XY>pc7l@M$Fb3$vVf_8pxHrzfPhE~ zS}&guy8OG}fuDGvvMy>SBYndTw8y-&)p^6N{q{GX0Li?&9oD|Xch1jwOZay&Z$*Wo zXZY>D>p60p^*IebXSyf8w(U#4G63xt`b*%~lNZqz`NWj#j6YGe8G54csh8*pVPh2-Rx}k)P3~r^QC-qdAEE^ zc)55$h~nMq#OAf=EO{nByf_C$z3&51o-MC)P60(Z%e>vbVJ`(QgO4#+IfXg%zIDDH z52D*K7oB0ewY+OS-M)zL*srZG2uFkWlb3+)_E}%~SF7vJCEiJZ)~oj;L|i z5dEI<=J@*Xgs-17#f!u<_1yesdS&@azl3lJ*vT0KR0F=f=e*gzZqE8{@mBaMU)R4h zJ_0Uy_W^3Yjoy9$)OYbWu9uJ}{L`Fu-|e?bpZT}JSJ@}t^Uf{a{g>s}#uxgB&8y9$ z-=Wz8dLN-)c^?OF=}&!ked~SA07>tTXE}?uCxEKKBj0s|i;GvM-2$&ssQQ+3)(WYD z`i<2kV^i;0I}!HPR-tdHG(2wK*{h;#$`%~om*`-OIA{nRQFWNGSG$AZEW4 zo}PO}v*lxNHbEqhhYNqB++anZX^DtBGBU1p?~Rlx6rywbaY>?KN&{vn^VESd>qCy< z3C>A3iBl2^jBhI7Bh}pj=i^pB*)hL~KI^9iO1plj3QBOSLC&Ju^k$AhkQ+l>qzrPA zL$xFq(^67q)~q?WY!~wMsvf?^>T%k{Z*XF5p?O-^8}>z< z=z*%zoRCVaOYCyk;PiPVyH{}!+pp$>8N+vCUq^UFgHYCryeY$=^WqzRb*nyWG%Dtt z56cS86JUBsFs$zV{G(DHSTUWl%d}lEl`)5kw_qYGCsbb9rT?Bqqn$6?WwU3 zFt!Uy21((1o@q;E#f_+tqP?QcbnUw8qI+H@w%+u7zjUj}q_eK}espNz&VSs-mC^V6 zSa+WSC;5iFm)oD+Uim`Dh+W@TIi2V|M8ZQvKvSLdE*orRN3jW2d|ACLMPuTN^g=ytc|&gc$>)Q*st z;*>F~j%#7?wB+HEbUjzq26J(CgfR!tz?VJ4NCLPbtvXL5usL&7WlB9D_X|H`x-n=0 zKt>G7If1QQB{Y{a{Qjcy-GBlbfxaU#rT7=>1V^En^__}+4IF0Ct)@;)-!CL zd2iQrPNIzP$Qusz|2oTXiON3iXdTC_%LAtqcB{-JFQ#hm?&uP|-f@I0q|bK_4#+Tn zPT}S?ohnjuqvU&<{RVZClRJ9No<7EDQY3Vv!N4_h65s*G{U~&!Rt0r$eoXj9)(W3} z*v(kaH(qe{?}?5~VrAX~`?s`LR$PMy^8_H;_fAFm6JIJm%khug3c!k+;>BB3jM{j; z5`vS|#)z}18aICRK@3DzAIwiLty#_Ch2#&T*`1MAUbddh2_ooAwm%{(Ipu#CVJgPC zzB%y+>)?^ojn`I4Ncb{5=ih*&4C`Co{c^1t*L5gFL!|)*ULl`U0c&umGfffr#EoniEdH*+obFF8G}dZ* zQB4M3!$6fjOIQvri)D@S|7v0CkGL2tTWKSp)OACfp|YT?HUd|=WQ{yM0dk1b_&7}s2mhCK2vGi(!Rb9NcXJtd$j5MrE2$1X6gA6=DvT!vo*Y?v|4BN@OQS@P+70AdY1eJCH_GITqNm#mxezm$Q)a@uZ|l= z=JsBtY#O(Doz(yFQb$?c3mnzS`CqB_$FiRER%f{XR|v2=M3zX+k;Zr^tG(}$OTrA1 z4!a?bVh#JfLK1ai!x#&v|8fbL4UT1hSt0wkMJidonr!@wv=0fXM+-u@0=T2-(pGH| zT?}u@JU^hcs=ANLK}ECT`qBD3o)~4vrhJI!LO48u8h;TR_f{qzHo_P;Q#QPq>Wp^v zgzo%J`kU61+u#?`z5jfEbmppI&g+6N0D1-wEjDKS5At$|@|V&6W&lhWz{BqLA%_pj z6ycIZcRDMUS&`ZzTbO{yvfNeM2q6)MtIVkXF4B#KXt>b9{F8n!e%2+u7ar2zLnW>J ze8nVOzDVR5_@8O|d$RuPRoQ%1=>CBC8d>ru|9HwjKYhN; zy!3FONBu0CpcRqNJSb10^|xf(ZEem_gm%IBZG3QS+~a5CX8f z|EY@q+1gk+{~DD)^dHagbRWR~Ac2?>mI0$f{HXd zvA>_rn;v6fYE{I5@^AW&yNx;3xrX`I4#J{TW`*$|&HA6P{o4U2kOfyJ78a$R+X>Os z#6!&+Yr4>P7V=zx-H`L10@jEpF~K3Ss*os9WDiACXqY{Cm~C2d?i9M|rL%_gOG)le z8Wt@qP*sdK>>V_YX2g5hJ4U@&%H<&^pQNdTz(`EA7p9Q79Kggq@i?9C+ovedtKY!* zf%R)ygH$gcwf+wY`2k?e(mmw|v9aDn$hJiU{?J*ox&J0-|5}58yruod z`aVkLe_;F%;r~s$!-Z*(4Xo_C75`P_8qq$|-dgDoj9RS|;X<8Z9QMbvzyTGg#x(|a z*#}Sgag+Nem;dJjtJ%MnJ1lF2YI!g2ENEJ7p{@M?rOTAZ`fJp%hFK^`I?OG(`0L-~ z-NrPq6XudTiie1yE@>^`kzX4S4t&t^|D05l!T(Fs`!}~d^8Nw1Su8uh@}Pb^WsRnG znFC^Hx`+P_6Mr+czmY-wkv*epmu>me=14NDNX@^Qr~iyM^aGDkCv`Q&;-zbi@h_kq zG(P!j)i9J%z5n2S8a6ZeUvFLbVgJ=g`Q)knVVzacN>AIwkctabmNF8uTKLmXRej=*X3ol^a=d+YD& zKQa_-R(;S)KQ4gklEC-fk0){SQ6Ymr75bl}(~mEIJt$ctH=^A}U`UjGxEIjteH#d` zRpvJL7gN#Sh6fhqqCa5bzx;8^fJNJ%CPbZ_4IlHr6!+g4{&>VdNM`u$Z+}@|mQ2Dz zM!WZ&vn?w1&A-2nv$p@WL7Jfq{2f}`tnQ@f#-SnT=u?L~LJrG} z9A!3vrjvQ~p|Hc@;k=>jedZ*p#N?(Gy^vUep~Gh-sYDRm6$Y!;ws6?|((t5jzk&FF zfX12fP7%kTVqLURE=&@bYLgxHrC|c?2sY%20dbI1Vf-{)_$8kY+*MljA18xb?~qGE-AUN8mQm^f`hF8YGwXqY(QlCcazaHF!Rr)p zK4=u&8T|DltM~VzOuPQjs1^PXD)FbWoDeuP{SC0owyJV90I#Pi2U(YCz5cjUF}7=4cvzXfk>4d7_lvq3MrTru=WG*^hPR0}}k(e!=fY{m_Md znA88F&Og%q|8bi|!BWd!;$W{1qF_I5OU?o>q{MpX1ZMsk86+OLmQk}V=C1=2nFK!A zbyw^Mt^QH7M#1`U=#u_nprMs)eG+)Kf|~^DEl<(2t{0o|6?!;8P@x(Y(_RAO-i7R| zyla8*Aa2w;Gz1p>{HM?=-V16RdaY0=N-$k-?67*GU)wneM~P=Y)*2Xdju*%rv=8hd z&5;jl11V@nERk3c1bdDBi2Y?oT~i!Cv7)KXlP1{DG1&HhSyv+Z*gSmLiT~D3|Cj6I zru(NM4)>~N2cX3u1mqa%%+3+0lfp>U)=0yy^ZZbE%KruF^~gw znW5gPkk18GsbiQhiNEO%mGu3ZwWr0F3)Z7F(BGG`Hu?U>pup#8YYW-ERtLuw0auG; z{66TKDbiLF{%Fi39`(yH=h4cc#C9$e>3pae^7o&+K(X{e+~OT^h)BexeRoIQy1OhHd=)YF*Li14)u_DlOklm8N+ctreO0LVX!SRjP9`G)h&iNh`D(;}H|z$@JrsQtZ?Vg48byS8wI4;47l1 zK0Sj0_=PaA@LP&E!=Df7Hkk8;G^aXV?v9 zd%@A2&@>sM>3hC(AwxtLgkLRBz|K7}T%%++At)2&0O^a*GImN_wR540`l<%WZdnxi zfsU)H0DXhKN)3z=mL$h|mZ0(?=h}mB#H9}uuCe!JK+!IuW#M=oN!k(uH#~PRd0VI# zRif0bXBsy9svkRg{JP_z!eUL-avx1tppcpLgBOIh4KQktJuQMItq7A3UUHbKZWsA_ zG+D)g=rw1ARl%}4R(HhZBc9O@Uiv_DLXw+gL6xjf)LE@-0>40-d&W;z zt5X<(884Q(t{*HERheq%(RrbM<-;#}*{Z^LIw{W=49pUZ*WzmqjEs@EcJNEF&a^iO zinhv;9ZwOm_1%D-~>VWVz5Yo9f70z&C4?`G5muufV@9)!Cu z0Ysdw(%{)S=Z$KI9d{{k=A8*7cf&VLJ8~!*_D+u)&)!0 zvno^U({fgLf$1nk4Qv!O-vx!R{Vm1z-IgqJqi86Jvc^wS5rB`fRlxZ$4ATUm?Bm1b zM50P@>qa71haSdLr#@jnH$UiP<*#5p`N9bqMGErKpwJo!fWE$eo4k?#SMtm>eBs!++p zAkVpd(y^g`Hfq;1f@*1Au9Z^{haFb>P*(%2V7coFr%PT{8e{)bS|Rz4K@w}Xnw5OV z46O%@$9z4Taikfi$d__W3=i?wYQ1?|Gsr%g#(9Db9-rt6|7emkM+Xf?gQ)WHvFZS{0t3AW7NU>aZ&BmudB}>f35UchgX$hM{B7nkRM9 zj`|8i72q$}zJnKq19c$#Pevw>IOXlskoLJb87sd#&wHrB(0&H1U&GjT*-*+cdvBV1YiG#f17BIm< z!X-D$Dvo_}V zMQ9Sut|L(f#4fKe_L=;?A#R+7S2rpEoYXWl~-Uzb3Y>u^iz|J zoq-qK^jy$KWC=N&N?mp2 zS+vHUG0&7JN)h1%ew=9nr9PVi4rC-Un}tLg({cskrb9ZTm%s{6>GhCk^3|W?!6f*N z2{7JeYgOR~LEKCbSNKg5dTc_UfO*a)XBbSER1~Xdvve)rV0-hfbk-EZT;iaA z(P)Yd!a1%NPy~xx7i714C%KzPw`r8rZ(!<-MT*2#7OG9&-`%CmWXX%#_%?FX>(vZq zc{#KV<fyV#fUd}A+xF3R}(+6%)y~KMIE(zoSf=JBGg4C=Scy@q)@ad zp1WTzS3X{tFIY*kz?PsJpCPrLP@IEK0cjrA&bBKUveIO6ElHt9pQ)h{Qf{J4V)=T4 zX>@K!nc(%(2D-U{^5Ufzl}t4#W-ULpUyBta85X>8Efwk#01n^vW!?g5+<9f?feMgj zLLR|3i3fWWxcrq0$Pit(Nd&K6>vPqUJe6`8rZRUFB9+zJ(05}ZsZo^#kM#^8Eg{tkNTmElS*9EI6zz4#ua!`C zmT+nPY6=<57Gr0;UYVAMiU=sMVdLi^ElaCP4$$&?P2UeguvMl~W7_TMjYpZK%iwtI z1Y-^ee91S^SH>r1}hitBgE|6Ep z|Az23rVYz_jFMt{t&RxNx9_Gts)c&b%tKnS$U7;YZp1d4JO7p8#5h59E$s!PJEh70 zzKODlKHGn&aqyw>bEGfrq``7)6}WPGsoGs@3kKDEF!7w_3q)!29G4o6N^+iEOb*EB z_P#rp_Ma1oDqezD)SIkpw} zZMcaviZmO0figkJlJ7serN!)eh26GH=aW;TFyFPJi(Xk2_-9V^xa22ja;G;V)cMXE9ycz}oSKq`!YVpIii>XY2p7+_{C=Vrj=&w4b7_Yec zBJ*4$?tf*b>rVKY#Nl!hN{hb*Ay~!694N01lD1ghEKiz&?lPE3HA295p4;F1bL5Mj zd5T#sEYex;zqha4Le6RTx}qlsYG%sH_Ek@pt)#IGT!(xovb^1KtLyy{0-w?3 zt)`Th1unxGz{x8AEAtIB1abnZ9piT1%+?EdK^eCq;(hJ*%A}P{!~>8i_hN$I-7^B9 zIa9jQv_Y8EaJskpNwWsRwXbzZMf8=#DcY?%jW1GhZpXa#eZ<&*;%cfPEwZSKmWgyD zU|B`YqHdNHkGW@k^k$5CyAY|7w|TjU4tZxwy&7Rhj~HyV2#R5s6&YeNKy`E^ixibRippr>c85;+(rTVd0JS@2+?Ux6gHO^$ zTul-u2Q5Ov@_BE%Mt0vF#&5H-f@nz8-{iAsY*TsQiXgt|vy#GsI4vXlC|Q=f?Y7}2 zn%+8kBK>S=4y|29B@+u9*czdOKDp9$-Z)Z(TKCQ|WojEX-tDo+Gcdv2q7Q4hNm^QR zuN%C19VQorRM!17r^vIiLR`-h#?943mY(k9$4eIV{Xeu<}laygn?~S0a`lsT67R6<~mfhRyVeaR{ zEhSZEJ9{*Y()3vJf|_<%RQmO>VySJ4rrr7h3w6l)Nb14*uexlU7{bsi`?>*?xDJeH zujJQjI6BMRxnWTUDYi7wux>{IY(CnZrdA>dNO*)V#Hy5&hA}p%auu!F*|m2UkK`l9 zJg(7Ida@jA?I~eEdLmfy)IpRlEGR7+@(U3Ly^=>kPhTuf4B(9F!-UFv&I;g1n-y^P zn&eaHlUH=MsGuc#HWg;#KqXnChtj*z!~Iygn)C`&jZD7{iOd}^CFUHXk_MxfK!2Xd z9_hBqji$<5))B$5d}(0LK2fut_0bG{ig8ec1m%%H9u8RtF`qE=0MebMM4__0IR8Gb zJEm{4x5g()`}hVi;SQ)fIExZ_-l1b%iJT_5;WKX5+@sUZj0%VX9aq*D&9>frUeQ{} zQ6vNUw2%g*>vSW!5dAU~qEYU^iP;2j8|o6Q(VYSKfz>vVL?9r)akhs8U;ByWV|U z!f3ku9VR*%YlivealtPho@^%F!spO@Ius4))jRK!l*%tmq?W5|)ghtpeClDB`!SB1 zNc<;QqGZ0;)%t7}plzs(p(<8b?H&*0_ZSw(av@)*5W)*p{Dox~fLb1wMf-!dqfHM& z2o9wU3MA#iE#EvI=ut3c908m>0y%ZsE&w*+vkYm86^HjIxcwblZb665H-d7dw@lrr;i$-W#ic3@y z8t<~q2w^!Q*F3O9gIhx0PG{!8zS>HMpC;ELpWNa!{mm_%BIO1tN1iK3>+?~u-U1%R zr&#@%GChQFKpAS(N~cR5z%mo647)M=IpIf3zN@?`ai3$GHWeo)-h{Sx4a1lKa;96< zcROD;DnZ;iX1_FEQP84ym$4qunmZ$b0@BAjOPp8)8Spby<`$_sB_$hLxGV0N+HE}D*{1}ePefrm-V8aQYMV|a+Bu4nnlZtoL7Z`_)(Pv|4tUp6K zVLJ(q$oT~Kna|=8%I;!p2|1Kb+A~y17|NJVQ<`7lqfg1VbO*S`r@3MTzQh?JS`hzA z=628R*hlbxzo`PArwd=O8vla6vtVmz_8hv?BuUeho$VwsypHV&f7*@NCN2Als zl}M6Y0~tEmSb-hvX8G0x!48+?bA^Xqg3Q`jFdGN#`YS(^0MwNGaWSY{t+@U9;2tSWi?e(#7Gl)%=x>Ofy_D zvazcl1!ARQppY*x<%&)Nwx^xtfB$1nEo#5ThfMEHj?OI<-a} zI-3Q3J}w8$#w({aZxJqZTrU%!R-6HMnw|cU5|rotxk?vC{lhgP{i_mQK0 zrgay>{a5XHI{_ef(wD!#9*($F>4kXS90bUxJO_2>P;0yv4EcV0FH0z0%Oa;$%`jS2 zgmVSPfaT1XL4Q%nOg4~u?4^*TX1fbd6m$()#zhv0lw?L!OGclEoZ5Voao)5Zx&)$f zMrHB3H>vbvm91z}+R08gk!ckAf*MmJ*+g}1VG4Yqxjzcq#xQkIC=4nYVzmONPH%Ev z8pvJp8x23`3L@w;UZam~#A#|RMl5&hGnJJU+Gr;zsSbm|9i;YG@8`J8n5p@%)@^cJYig$B7IB@_lCaO@6GjyZ) zA>a+M>di{{sj4sDOn-;oy3jMJHb7u{^gq`nfa2Og637uJiKJ?Jv`=96g zn#Rj(#$4PgP#Fyj*K(g}JB<#5LFFl|KaS8*#lz^8Ot~Mh`Xp`F!L(yhyG*%aOr8h?um!6tp*;bz2Y;x&ZMgz*7r+>{!d=;k; zU#xItH2wB@0x8?99ouK?%OP;u57GI`ELbf!RBNVu%UFjHOh^Kuy$-FL=CA#mWI`SG zW4v6-yx;pPWCy&+f||Mx;z^)Dd${J?1MI*Vyr?dUTfW>gi0qQK|D8%=*rMlOFDX?O!37Ndu+aP(+? z*K`nzz!fVe5_b|dEH}JeB^weFKn11daDe=Z!llAfM_idl&S|OL8zNBrjRM0Mf%2Ukuh;$BTmO(0isNTbo+yr+*DBA= zwNe&BX})7-DM)og`x4FxYkPei;ua|IA486c{$?z#-zJ+__UIrkG`>_o)Mk7R=_oG` z2sy|lHl2Hj)qBxRG^Y(1+Dk}(zv|dLn|iq0+3ldJ<42JkItsc@nkG^JhRRyRlS_!@ zajhKYOMd~(`OQq@`F%xx()Ck)1}6@=Y*EYT7UNwj9B0$yK|JFHt-j*pHjc3Y(6+D-rhA zzyc7Iypv{GB(b~&$1wcBB)E^cG0AaeIp%bhe4ojf-j;h4DtrHl-MB? z@hl{p(S__<4ukXzT+N-G^C5g_9OM$gc^R#C@Y7Azk)>2|-D)WMYg)$|m+b2<2dZvo z#;^q07f6XR9H+&|UWXglCO%0-b|qu)dY`cP^Mg?{VJv#8Oy>qpP4A`OrQtD$h1Ka|-Y!cfp5c9z!6%%0#q zx6F|(R7^4OT#*%WHZSae1W`me+E%xGTfguN@e3C+mxB3?z4}{Syd#mQS!Xv>!kG!T zbz!c!vNq)A6);Ia@MPYa1|ksTp0kNR)n|57j~D0w0q7PVTB+?qxv4<~EOv!?`grR~c?Rl0h|-If;*=s9CrC24(N!%gftu6ii4?D5rd42rBi7Viet9S1hDx%X4CCzoy~`It|jWae{fGLq>G4axZPh>4DS zyju1Ul4ZT z?PU9rp+8D6Gw&ta=-&Kj=s}`f<*QU*3xvL@h=iN!mFYyH+3~8Z!(JU!o(#r-k6o1e zcHs)Q-s)EjDKn3=p-D1IKGF)I2Q~z50EQw?(bZnt5QQ97DeV22Zq|_w!zTHAb5U=N z`l8-X!NhwAB4=p+dv3}O>=5-F{nO`;?VRmOOW)@zJ6}HSKpCk%0v&%zp1Pt6hUkj`=8M4^{m;ovnJ$yPYLi~)$Hizr&FrdH}oN$PAE zEj@e&v{b`4Xqp`+Fzw?)Kg>O_Iuh@4n_~TChnit$7$^0`PKi!y@Lek`GOjZ0;K&TK zN6v?W)xo(Gf(YcED!hD8ph|KTu@tNb6xTR-^O6o;OUv)gI=9v8)0{m9N=>WlnU_hx zr|ayRc2Y9gr(jHIy>1fCb-_11kD#N*81)hf7&J&#K=hi`(ID&02nEp`C$a**p+ZC& zQ67?#_#Gr;kxMt;!u=ZiZkbc^r2?omh-#2FhFXE2Uk2U^L?lhM|G2H9EBwVuwyC8boh(FYDFQh@JiO7XzZkTZKm5asXA+M?#FFkCH*pb-nW zA_3pZl=AaY93@}3Yih{ta|L_^9SQ|_I>SvO$s*EK0g~70KE?CXz>_bQw#S@)FgN4R z3D-crj75H#&~R4h`Qc9Q%!G}2H@b>&fgMJ#8^M<18hhA6LbOOpB?hynq&CXCvc=8w zzkHlZpB~1>$}>W{w`)+}Na;4;I(Lda><8`LT-mCW_+91pN`^dyDn*UipWQsQj3Dj3 zmsO?gTO}sz%Y|R0gQ;YucNNE94=Q_o4!Ex6zSrO%aEC`uS2PN(tZh}&m~U#Vsua2a zSi?`I`~mHKO5eVp@Q5XF?tE_FJh#{AL2(971W_z5qn8a%R~$6%0`H+j7wI1m48O*n zt*aEjSdO3j2`$y=BlS6!-4sD_$@NvS?Fb+KXsH%AFw)*-TGPq|skt3&!+Wf#rWa%* z)ax>20c6q@i-^Zp4Da@ZjIvBtn6{~?j2@l7ty$bM}G5J%>Oe(EzDuP6^RQDqAAG5p(7u?xh>XrbIl zt%R|F=c;=q=prCP02??7InSVyV$0K?+Gutz)Hv1SP2mz;{%x>Kik;jz7INY{vu3dP zZ60N>04=c(URe`tu_vv|10pWG+EOFB1UDD|;a=8`HuwB(z0vrz1e1L849Am<_zc-q z4^%7=y{&_xgGovgrIlclHjj$gvL{il%pzH^!?d6;wa5yeixF;B{ zm$#aWd?*mq`HOVAjhPL}zRYB2xyHCPslTS`A;pP_d;B7CJ!0{zeM+A627I21^O)a- z2wDQa`Na%Ty?o#It~%d;2`yCjXxtmgbPV$Z?v8U%%)U1FCO#5rK!k{DOqK+*(Ki6o zq`>@j)cDAB7oVA^+7O_VGZH9b(!ONpn+d5?f#Q5x4>l{u$Xd`xA z2DR?M%gR_z5nD~;o!i{)k)5XuQ1uXjdVsb$ft=QrM-Ys(>z#JluC&H}k zLbM>$+;RxjLK-}Tqou$Ypy1K8mX~N-mPBeHG1D?WDg1RS*``x7&1fv1-Azm2OPVrw zS`x_>spsODUMWMEY$bCYRG-tuL zTb)H~6%u%=bT@Ear~(Pwu`TyH(<+9PHnPBF7q3FTs+jYVS$O5Sx8EMpxXByNmJM|e z75qu+^+%+SbpD_KQCV~jl~!A_dk~Yg_*dryE6daC6KQ%%yY(+}z-hKZYnvKrO+H_P zBtgRB!vzdmfO!N67VHyg=ex7+N3LTp7mrNOuw9mapx`o0VtsD*0Ny#wwqQjKnruQW zk0M-^{$BU&g(mOPq7NQt_7l{CzC=!|=#ZECoC65A%D{FUzXunC@iyD*xQ_aTp70J> zQOQ6rK(39E4|$f_DcrtBN%rZbkgdAFDb&y5EA6u+lK{?ic#)>0BLiFZEbEK6z_fF4 zM!vJ_Qd>cs_$?+XmFzn27j2SNs_9f<&_f++t1l=N`=J-4S-9!nDSK(LRgv0M_lWgA zcY^W%GKQVQps}$ps#UUQ2}=gKO7QO$=|0&rnHFTt6l69~a762b{lq4Tly`3-5#@Gx2q`Pdc10RyWw@tbSF?FRi8Y}!O{s9Y!&9wTR|QN2j$ z=ZSCaX|54TMP;CArO;zVYdh+a{m8%ce`XB-VY(Cnx5d0J_ zqP{hX$~ZKP5YPotKel38cz5iDyo=SAyzZ)nHlo(n7Bv*V3^x%7PV7%4{~@GfpwEm5 zs1gHJ1fRfh!6ONPSLuy_=<8jzICIc9zfc^?xb{Z5&Rd=9nPuSPxRW zaUK<;!U7F*5%jb;1{2g(QhB6MC^oKr`AwgfhpD&>za&ettZZ{gY0jK3F9lnErwW|9AIh$nb{NYt) zN4kaj6&sH}DkbcDO$>Kei~g%X9pGlXbUz>~n z^&oHIc>#tfR;5)>sEWi+kTJzK=^_SM}SK_PF0${kww+S8t za9ebe78)+9OZq}jlDKa5H=83D!wIaqs28Z9^*dY=2NSXl7IoxHsxUt1H*;iDrCMqp zQTB!GVKjv$^V_aynu|FO*M?+@R`9U69k?iUQ)fb>t&tJ0G(=D>OIsHVtne1~9Y2n1 zVDFm2Y(MJ!0H$>nBU}Uw;4Nkj?m{tIciyA8*e1N4TfPQEk#J9T_G*Q3R^RelMrPdn ztYy7ygTZy=tQ2?>qV5R^6jY^60Hv7 zz^Ny=DltKrCt!$nOJ1D2;zSEG55!=~<~fPPLNDXn?f`q#v)0CNUoD~W<3}>Lt;%B? zQjO+Sx!kQULGrJfqqQ5;(AIjGi2<&tK*ouj@#pU;!qmlCNnwpdm{JG#stP+Hz>pWb zTCFPu@29U$AS6wcY4JKLnj6GEW~m))@|2zu(9GmJyY-qCz&74TlHj`w-4H~$0DO%O zgYNc#W`t^lhftWXg1-6kEI>2Qky4zGR_5D5zXzjAWWj{~SXFHfa_?!Is3xC5Nek82 z!ITr_M{HhKV;m+5tl^s7K*P7)m^kUq6Q7@^N0%4u+|_Eg)f9KQ$4VBhQZb2F{VLn# zZ=pIX(%t3VwZnJj5UZB~K^=o3LC zGR5=o%tUG?!QasA4)Kw}k3$cSW5YxYjhYUtH<-wB92Df2$(9kAvz@vUQ8P2)#&HoHC74HCS`<@IM7dEP70CqzUz+BLc# zWoxU#*ABnhw47(r1XNkmw7_Gr1NmwjCWWCGvQ?bDEmpNMiidv>Rysuxw!VxCT_5wHF^i1%6bQ~0K+OIcE(Ie!H$w?86mJaDV) z7HEM`awnjRiEMy2I)>_o4$Bu_2^N(R8u238TTn0nXOIjB4O?{C@Q1)N?R4PL(z-I^ z@9)PQ+sH-mgTpI2c57VuLwt?QN3WKO;{agic5znWk~PBZ&N;g}v-U^nxSdge5sVGL z?y=Yp`Q-$gccOP-aMYWk6gQ{#{2Gtjk^4UD))Ej8-xLlJC-VkGaKEH^Bidp)k83-* z`#EkQOFvK*q}bWn_P!;sYhp!pyvq2@Ups*tf5k1_4ql-Oc7RSFEY9^j0&>tbj~XU@wKr z+}0#UfykEZq*xZz@fQnK!mnOAm(Y}C1UceD%RZDk?T;u?9gRQG&U87t4@(!Dy?foq zZLu7!Iz-?8`Hs+*Z-79jSkZF!?HB#>^)*=$69Jn6#r`|*?eG7u(?3B^e^_oNKu?02 z?E5Yv)l_(ZOC(Ses@S5*SPm-S3KB!Gl#YuHN$g;_CR2`;1YDIN zf3=|2zd;0Hzm!RQ-V?y8J!*!*r8+Jaz5KYv8)4_($XEpZFcumCLn)f!7rJfc~R`?q1;T3h) zl}}CFpaaj>R4A9*{V^<8-G{1Iwn(9+SGE3IY;=gydmKr!@85Z!ij{8YsGPOH_9+SDaKkCszf-vOj31n!M!cKU>WvX3YQIELik9?|3gnf`%ZIm`()eoXKl_ zEKaCVp;3cdzV^;rK!N>CRs+n4tlOZrAL2F4F9pYc^H8_BA~QHq(jG+}^u4))YYGSm zlHsQ+{PVq)3`a6S0dk*xKBTB_XdyS4M0GmIOMTML7v31Rc;jD7o#eG&Ig1^OG-g`+(_u*~c!fHa=&CNxxxe+XczD z?{J}2vK2;ae)@$0Xb{o|vrA(i1wPOa+Ldw7R&zLI_Q2I6Lq)pCG6b z#0KNGuSs%p(+^5Op3+i!kXTwbFE<1;UNQRvEp1{LIGo{UAHN>-+R9QwsZ_UC`-Y4H=IzwES8E&Ww8*`MH4bf6$QGN(AJ6l zkHs4J;aN1I} zwY(`}iUu|njh7S*J9!n!DaS7Od3`y&aW=@ZJO#m*U!&c=+18K^^5UM1p?gV*+^JvJ zArM4>bb5@XHi#}Y*GP!=B5L`e$(EO}1@D-J9$(*r)g`{Q1VfOW!Z2jsYQ>`3o_B(m zDn4N}3|Tc_;Ncr&V<}Am2?F*EB>5r2&HzW%j~$PUt^}U|2&Bj@YmD)6y1Rp*9iA$N zHQX{)#?dD2B}B7h}8XwifDN6Wx-qi?i#f) zY6nFqUkg{xinX>5PeTmAR$#t2di4qe1hfD~eaWAbp&4dEj9FV1VJ!~9_e8HF2yqg{ z{XOHhB1A>KXDAd5_qor;t-qF$YF$6EyfNfH(a44eD%eRaCAkRxgto&PgyRWOm*Iyi z=%EOT4&4f7owBJ9j8ZvHnFfU0lN+R1K(nKyK^7ES;BaGpMeJ=e9+kT^9#GEMpGbx; z$3~-^z1qvW%H$cNRPRDcPFYx(0e7if8M_YbrL6yUyqV@;0Gg|UxV7p6v3EX*!pRhJ zr=`D`wZsXZ4)0wLev(cm*D7(My?IToDAFG0j;J|o!7Fz9bxKSt>q#)t{Bh_y6$f|6 z#K_>Xd1-sG>e?63QxXw2T{v8o4vJ3s3x0W5t?z0cSxH;lv>qDaI)(0V-3Ow%cHgGf z_tHY-4tuL%QN{3@Nw-r$Mu8eoN2r|*1+gx^DE9@JjEe2KvthHB0V2WZQ+=Ib*C=(n zm~0|8sOOH*0_D#l7Hf(m{D||-i!NNh4pzkTYj^Kh<4RC4u8MTa44&iXPrVL{(OQFT z5@uTw6Hwq99E);@S(}a3R4>*PMDK%V>T<2=ayPnS*<`}%*>gCXSU-LZ`p80In=cbL zsYIDDf&1H~j?fG$8QBX^oi*Zk6A!OZJRUn$T%zZC5S&h)1P<}z32w6_mu|r8}*l?@$Hi77&%%A}l+M<-4?{dOUfXaVV9PCUqB{f>NQ55ke87Xc06b14I^;148Ef z@c#gNK!m@K^kUAw)ml)=Y>LA6+27OJOY!@>IpZi!=2qqGKcV^-g766mr&NN-3FzWs@Lw z3m|dd1YiIF00b8jpI9Fr`8s=DAWFrg0#W)}n}&`FPlMTye|^RwbUK37d!&f`M{>y) z@sCqt<<`Jt2yAAPK_lp^L9;9i-IL|^UuqZOe}7c>tpWi7bO5~>y;MT6b&BnAe;a|> zAWHebmusnII9)-PsSDkMf<*QaN2y~Zik9&;gyt9?5v&iP)2EqlwLj*GR$S=fLAS?KXvnv)0)q{K3V!ID( z%xB@9HKQw9?BMp10?0~M?QFJ=7#G_#qGIBK zq5&c`000017&8C>000003o~PFfmFYhL;q00^{;_9+)NPS3^+@e#ykYF>Pum<`b+TK z0|}nE%=kpfrc~~RN;T8@bm1+A2mHKscu+jf{vjd&pF+5!vP2WFi{7}*_(aL3RPKgI zY5W>>rr#&EkHh1eaG(JDgC3EPmx<=qOS*QAi+D;usC>vz>Hp1pP96+Wh+sA42#3ox zLPw9D^B=1}$q1CLvAoiZQj8Fl#MVA*I<2jO=~D8@FH&?34rSdlG0oQ(c>rmNd~^3J zDe#v7Z@Gg*+nPxsZ_KYZuv{r#W$R4k$WSi7TU5~&&J^8w4MTde8M0!NYN%|lz8 z?!kWAtN83_{2uI8Sf{epRIq9n3JF|+{mx%!k#oT}r)K@$Gdwsh2ud~?*TORtNRBGU zfa0p>HT5E?g*kab!O(&dA~PK;HS|+pM{~^PktjcUO=XA;)MI)fYUE`~UZwZ%G8`5b z2;q!m)|nQVBu$KEGu_914O>M%>#Yqhtrjq;h{rW4!h*onF?*rF6|@nhx0>(<3=yz7 zAPxIDLsYKT*j`Wu!MOWp^mfTb7epwOp6{j8>Y=%FTFcNIk@X&02~%((Ad+YzsCX-A zL~*%U0MDif6x#r=7{uC@Hze0~PxkvT_dX(5%ksA@iVc~$pPNkV)E`hzyRI;6R|FWz z(7_HHY(zY)SJbZpn2vkr+x5HR5C!0z73utsT2dzRTOGoz=N z$j{}mITY;z4+yeZ5d9FC=~ba?mj9(Q3mhxY@RWgVN#R7|Z=zvYtE?{gDhaqZ#A~tu zJx25*Z_r>}U9VLZSxho(yQw!-&y#*{xkw2`iT$RL5h~~CylzO{XPNfP22Vruso+%e z=A{&}A`eom{rw(+nBam|Sxr58qt}2E+*^K3BcTF_;8V~O{5-U5dj1z{Ek{<}KqpXS ze+ZQ%qUAZcuu83E0#XFf-Uw`&5`C|HnhRZH$>0fHhR(Qe!igyt$B-Yi?N6wvW? z#VtjitA+%DZR$S}w0l@=ot!M2Rlh{BvGBu#q?$68lj~Tjp7Dx)^*%FbYv=RpeO->z zfYboFRyC`lS-G{|NhYz7D8Se3X7}XM}@h2 ze`#$Eoml^g%9P7O1U>fSGa?1RWcPE}P3J_AiHLfOgP^MNjDEdIbC_5Qj-$%}OyIxo z5m8E&52@BfgaUR<02Dy~-C6q~W)C2>vDfHBQJm{?`4t;ZKpi?28nlVvzYXko_05sJ z2Fm>dEkSfHyrX@titHjF4HvFt3|y{lw&O3uy??8%gx$W2#A|dQ0kBIvK^x9#R6H9X|#Z@M6Cu4TpX!* z%?}Nsa{2z4x`a(cglek*4#b$oe%!0VSPJGRE_HiUR#{Hkz(Ec7+b^wg+J5RJJctK` z_(p66o2n%Ai_bFynXaM!UJis$Ta*{9GB9YC>lB4S&2Uc&`4r!=P^|?R9cLZ??UwcMl+S`Ak zORZfuhKwV6+S+hUMNHwWZZvA6LP5x0bHvktSkscYTQ~w-A^4I7j&&;cC8ph1Fzk5I z%@pR3iPF)S9}Dn>4<0hF0vEr&MrV(T5-`VYp1|9@|H?+#I0Zpp(A9E1@?EhUeu=}` zDIofCZrOU|LF1qN=ts8SLk7u-IppK{kE|uOn@b<(eH)zo7@)jHrGho#8n zZ+PX7Qi!t%OrLE#6fh0Z8p>7u2Lnfhx2O2hf#{aulVvMtMj%!bosow!wv?}VE$tKZ% zCRX1qyzd&?i}>1NjP7ke3-HIe6hz?3Z~hm+fN)LqR!7NL)sfk`=&`sIZEr$Ykc9qg z03R__YNp`ciyL!M3RM=5%qznJJP=WjE18(DRBcFYC5(yPssg zk>K3~cNU3Z`Gftyt4D0cw2)cF@C{F5mkBzH%(U+N*A*7qQa86+>746k7-Kkbdq(7h zyND;n+A_-1$b;!H=28%=N{#7OWKRUMqXDR{=IY2>>rF3DBQe?6m(qkF92P~7F|3=A zl@w*Z)`tYwaUObSU~lr=8O*~cCDd2Z!|;>@15^vN6g718ynXj^&+luPb6^a!UvVwJ_zbC9if`hV%dc0G$^s0pxWw&XJgNP``FN>6_czb=y@XsmVu%8%l>$ zZQ|RbPFKMbLD#)BSQru&rLO<%=nIeEgB$|RElTeY_%md&99wd-C2+qPQ;bzdfYBpE?AX#h z9^1_B0?bX#Ini5u5cSdDZ%`8b@uc1;Xf2eRF{oli#KCQP^N_ejJ3^&uAWrM)a&2=` zV{^-2s^co1?K>j0(&-exAyi>Wpmw;ozm!yua83#Z5gUy-z6~t7c31)ad`agK|61?z z`|C5D-MpYo_a%Kkaqi%|W{7tdPnbT<;tU0Cl_s4f`0x$*S#OL$ZS z^k&hz>w7zRWg_=Kw7u3mSb6c0Rg4j3-(_FyR+j(KE^>49y>FA+-WCAwgkg&!N5qMc%I;NuFU=h|y*c%9j2< zq>26OOy=Htv4EXeKncQc57$+};rE-00gfmSVI6BJL1bEbU^9RLRI8GYV0&DU`-!hy zr&;`I4h0Sp2|jL`s4sB*s*A;h;SCr%Xw~O&9%5kcl>7$%WL4Y%a?bLa5)9^p`@^N+ z!qmk((!Ez(ANOc#kpp!Ephvn2@GZKGudr4vR zTKWv(wpy~=lxjTi-uiIJTVob@^BZ@mcC0WDrRX5)$v3jdAs0;J|3*agfdJKO*e06%Fa6}iIZ%-KrGkUi>DG) zbY01%+IIPH%66vSkUsM%FlLt!fwIZSd~pU($;wmO)6%d%^*5hP6M<9ic`ZQUPFU9Z z=Odaae62s&cu=1HW`lEXYUyRryLTZS$B(&Yru3|lM1TMQ000001?R*bMb|9Z27N$U ztS?5{gdJrg_aY5|0008KM|Y~{X{FNh!0o1Zyvp?;>LN>FA!0gNWl}U#WsrNz!J&;d z=faPcS6ONgiH6i?%2+q3b4R@K@*X-Jg*3bgriM@zAW|uZ!!Pa?y1zUcO=E5IsyX}u4g>8vzvfYG*}pAJk(hBFx; z9&=X*#kq~I>B%oS{7AvUHskzOdr+*^sD2A@s|pqX^WJ!)0Huqzlvd~Tu56TLOkq`4 z$E^aQm2N0T^0KVYLd(DC4pZZss>Rth{E-;0fl4O{t#2dncM3-|)ab5hb3-S!s2@NiU_@EJG&p)yuWmTga0(rc&gG zHbQP7P!Aqc$NT&3YSpzwU!7z&(yXs6^#HzNp|IRf4sC!iotpaKhe-&cZc6VoP~LI< z4S<=9Pc&9rRK)1)ejfa-*0yI_2L(q=_v4{(az(cCkCEdZ;n*eBn-QgylU8xN60N$C znGk5PL2($H`b@XLQa4NbRfye29Em)CW9FrCX3lKo757S%!Kcn<)PcaF0aD#U=APSm ziw^($6sZK>8V7<%X#Ts$yqjE)j3XN(g9yEVJ$Y@nb=QthpW`F!M#b9$YShas)Kk03 zs@$0QT)js^0&taOM!PIXCJY$GyifoD000000005Qx&A|-`@zjr1Zi<6pm3Y6j9BXZ zhRZ2(c$!Xo=T8|6Rw&#H1GSWDNAKN~68B)S%j*VK508 zzt;FoQ%FZ)0kjwlzyJYylx;+3CDr+ec;d^qNajDebH4*hCU}46tS)6jLXd+;3ko#@ zvwsO*#je@Z(!f+SxB&-s9H{3ix&31AZv ztBA+b@)4k6UJ=3BXCEcY{vF=|W~(vmmj2;zZ;H>s^>UKxh`mhbb5GhAjSA5Ov&}}=Y|9qHwdu9Moe0pK z$&0EUcv+|~s=F%LSVqTLe+if<6W`h`tY+rw6an;Gx9C4?hEf!4={GoM`Jpwp{ppch zdVMY<)nMm{ev?X|rz1>4293DLD%gB21@~7#mW^eBK-~ZLXojZZbyQQ4A_6Y9=nNbu z^mQ7Z)kb;q*Q6)93Hjm) ztjztFikz+2cxfieBpv_4Mq*TisU)NtkTeF0dz(QLf0X7S4wO|tx)%fAN-sgM(8Vs0 ze4`p>3zA(KObw2KU+K~k=|dm@bN3xMnUpKF;hz*@jGug45$&Y`LvUK7iZBa5yNnT2 zhLKzMiE0yh356b|_(niS`CJHmh9F75mpMWl5wZ>kDIH2IUVfoiN=CX_LiC?1eZVBZ zJkCRij#jcHi=ddI-T`8Zofh*}nQ@HNp+97w%F@!|s@5|aFeV zcb^Upyv13y3<|BMHWw0Tk`6NcmMI+5=Z%f(w@{VyB^2i21tKc5i8+NvDB?O0K^otY zxR{OW^wj}3ohXOm-I|jc6$x*!@wF9I5_8Dxj>@47rsdf0QUxjT9nt7#G_Z0S#^4H5 znWW=%rEEhS=$9-CrXIAU7Qv>*)^qSW#+77=4D+N9V7k@&|39!3I9Ghn+w>o@-;it=}DtS&F!I%k}-00jL<9ttQt>ZKR0f=>++bYDLV%(vJNLx zvK11I1_bI3ROQm>8!lP)T7oXbuEojwgJ{qEYmks?RmL8AH-Gp6Q3vy*4xr;%wl_-j z@n${eh|m#Po2?y9KeyM@Y*11gOts7K=!#AJ9eDJ4%H61UunAoF97*&YiK=jx`+L^!!FDDDUJ_9` zPRU>;l#%CtFf!o`jqNX-;XynTV+ehR_x-e2FwG8llB6{cdyE`5|%oL48WpknRdDa5Wu8K|0hGvRUCwc%gcJx~8 z{l|=)FnN;8bu>^~<;WRXCHqdQs~Im%s_<^c6jN0Eq0)OH!UACyxy6> zlGZ}wEWCQoev3qM`3QrIvLeVRmB&$6;2yrObIMcu_^*T6FCYv(^s5Jp|8R?(k7b3p zspYjOxG|-^?+*_XBl#T`d*JRpQ~J#}LWJmR7$6ajeu2Bcij_)-*n(ooLtm_9TTUcq zDGN3??3tu-B;NQk7ZDsu;4=!)o%X2SkvxE6x5-Uxcdf?nyE-0PANNO7+6RND-H&e-@i8EbIkTo@T^y2CN15&z#QNlHhfA&ln z)kTn#p6conHW(*djiF2pDl&%tZkKtTV@oHPLm}52Al?}{7g(~~XsL;JSo|5-zlBbI z+^=lCw(f+CtkS32Sp*%o6wr(S02jUhJWOmItLzx8{^@-1tzePe3 z*us$#ylp>8;&iKmTkQOy_jpp03-gJ>c2|o|CP>c6#6e3Q!^Hd%K2{WtN~>O>*o;Ga zj(;l@)uK11RQp#4F5M^P-Z)$bn+w0Ap`f;B4e<*LmS?U2yVIhgL>$UysQE)}v>Yf2 z)>4xkVp-o3{k2Wvx1F5xHq_qeg47EqGHlGV8Wl+F3j^ufK%IEtFwzOR&?mu(J!KtD zac`l_p`l0svAH8b{2>^nJ$Zn|#Oq}Tq?$BVUA<~kfVnr!@gyeS^-&q~LZK7l^h@ko zq|zuU^)H(U;f9P6GA;N$IvX`gDN1I-T&M%Hc}(*o)1~}D^NBymYMVG#4}8d2jxI|9 z6WoVy&HrIVsQ+Uuy=_-^Ov$>^P%rOCN3;uqw>eIRa5ZFWd=v!rOhn6;g-}E1>EBL%Khii4={w z)iE}z>~wAK4%e|fj-q?jWq6yaf@Z$V<*a#E9WNZf%s7btee|x@GKEk&zg1vZgJHk! zng|qk1bmMd!vOl#SWH?l@uCtC-f>P*Tjt|4=rwMSJ{e7MX53_FasszrVpQ{8Qv4^k z5LM#XdYYacjvGn~DAtwC0dx|XR9JGZ*jX_ZFo`+h!p*O>i;T9b+d+nv!K*VQQ`1tB zYY2yxoZ)tQ53O61G(Xi(z6kK|53DY;_RRRtN-FBb%GukSyTfe$s;B$yX&F_R4HB|+ zaly2r(nS6&$0+KqaqPGAY??qJWM^l6uFJBj?H9qr|@<}CLCvu7SCEOVsqR0SLm zj4yfj6G-V|0`}(zC!ezMoq0x)nVhzui)Q+P-9|f6JE_F(=pORS1ALt8h3Im9cXmtQ zR)yZBwJd^Dn%?p8OxN#mn_nPed(v$irP@^oiJqiil^>BKj-9)iE+sxWJlGCRv5GbK z7FCNO_VvOzGZCIT7x<^T{l;j~sga9!QyVl+}U_Yy3FtcV@Z@!*8q$J5ZgK zafWHwlw4@y%PKJ&Z|yv#O;Szow3cd0> z>}J6Qq6(t@HwhaWHZ$TMpyw;xdX5~#p}RjMz2}071a4Umv-t}~3)dul?Um?~vj-I@ z{cK6mib8eean_S!v7#&83G#aC+qhqZ$VNCf8M!bB6_;Y>_>t$75RiaCo0Cybeja*b z*$Rm`zJUZVI-=q}4tu7tWaQ95hm*D(|w3O|=S+P>mJnT{Cae zM0MmagcFzV@i{=VpQ26+;moC{eq4c~91gj#1u0%P^Ds(Vvn$~g9?0!07TA23%e@&i zRpEwn7sUY4Fp^$}cm{RUyf8D;+gI`qBn#m8M$*oKT~n_}mZE<0>Lq5F#q`6tB;D*0 z=?G4lL_?;Bo5@E#o-n<(?m<_zFoTk9Dyx|XE0*v5|6Z{%ai8d1%1E>V(OYlM?kPS2KKg0fZ^x ziG*xDvbD1*imiQ6OY)|~?x!-4)8=aVu}>Rd7|Gd^4eC&D(BOB~NpDB0qvf7CzGfw5 z*j=zoapM*V_k3uM<))gr@Is6J0lJzu-#u%9Rbe<$#&QiU3e&FggK?F&5|}CsI{(O2 zTFuu7w(Qn;x{ijgi*rObdED}_##c2P!S6y!2IvT1Lzev3`_(wY^j6CzwEYf-6rxu+ ze+@c0nvCJB=>u!363Ofeu3ygBmxLdBXkW|^U`DsnrOw$n8n(}5vuvW04&2%*Y3<~0 ziF#;Gw=K(fL%%eAoXyX8df+-&Vi5us$s zt{J^W8ao6D5#C(lCbFmi00070BRHwSg{@vwyNU-X`TLkg06LBRPQQ-}eJ&QEuA0x~ zus{F-!s_o>f_i9n94h%smPf$pzfvED1-H8+bjq0I`Mr}t7+QH9CwIJeeVjif#8(8z zm@-w)KNnq6uv5sxYl68|lL`T=ho0He!6o$Yu-EC{0JgY;iUB{sv|nmJBwAjeSTtg?HP9$*QPJ_3f&F1g?mbq7 z`+M`uT14do=JWk>yI$C~q?9#PqHJ&Oq`^~-fX5EfG)ADFe^*p2RRPN{n`ix_xID9StXB96Lan5Kq&#rZ(&<=TVr$Tg z<0OCp005kiqwK+VzfiC90wkce|L2prXE!Ye;S8pYfMIx$crZ}kitU3$x?LGIZQxfc{2QOE`|)yGr)hGBxFtB@P%gj{h>J+)XQ%)_LA3#kp)b$a7QXiA z8l0f4tZ9uTr#jpe1pk|HqGFlCKpL5Z&^=yKyO0puEN5p%d<=w-NiVODP+j&>cBAq7 zb%QnlNc_+=4vWvA+5^GgA|?P62kmYV9&Bd9r`2SwR^z!SM2f zSNlOY(GKljI}G_`pYIhZ#Ry(=spLX*F%1n+AEx%sor+JzR#fJ;M5ADla-_2$eW(Bc z96*VnYInel`-uYIViQxnGLv}?ox>1<@Bnv|Q#iF4d(d`+XLKf_G)&nFKRvqjFEEj) zLe&$`Y>lfB^b0gHVqOjFy=(#W_ zu`p(LUijkANBt{h^qKm70yJ&8Po!2&lsng0G{cKGS+dhyx|+|!o9l+BLi}3cJ^ky9 zf#@oW_vs8NNTOS-zuPXJniXBmlBmp)lJqLZ5VT+bFDYkNvPxm_{pfi`H0uXsa%wGq zdYzJQv-TxA{|N;aN%CdV8Y^y|pt zbP$=f6h4?5smiKqV|>qvOeVX*w6VEsF^g=R2{-11yzXeH7-_^#98d7UH<9MU=?}%v znc?Y+36m4zZI-h2J-2YOk=CsJ{y*GaJ^zaOL#=Wf&NMERCvx*yv5|UdYJvU|d0O=% ziEEZr>E#7-W8c|F<;WEMzqqu9zN`%j{aPNv>Ye2dV&0egQ>MV@-IsRU0gr%E)}6}A zD5$3S0{L*Rgui>F11^1+fb0s)<14qLbJa{ft%>}gl0T2tV?v_~!?xFw$;9+?r@d_< z2k=Id+m{Hm%5U$U{)GKDcpQ1YD#E+N=w4h1;u*VIyjn<>|n#Iso1TQdPGSyO&7$fb8O{PF4 zOa6eO*1Cc)+VZP!ISe43ga^Ne|BP9coHb7M@8aHP%gP*aRdW}B^!O_tyy60&ges_cwFhF3$4H>%HnmuCc5bi z(KA(w@n4RRw%@CcqN7glLAE-M9<9T<*^=|xHU@s$Zb~Vn9V88{caKWkL`PTX#Q?Zn zzI}5ekZwGmHAY(Mk-7<#uDq^9^t5-$tsyCqXf>;IQ zgDpO|?Hye6Iulw7 z-IaY(haA#F5Y~44WTa-6rCKGFsqjWyKJ^ zg@?X15fl`kB+3#cSPIJ~e1l~!2HHFVl=I&_Ib!vd`x$spkr%%loS>7~(hM`P1RL}J zkqSsE8?8p~>PY3g;_(s|vfoXDdQho`uTKzCeAar7YUQ*IzD!@N+V?MmkUWs4g_!bSDC!5-G4_Bqa1ovozST|aueV83Ug#?py0Atx6Hd2< zdO3)M5pbmFO?XK4FeViN=w7UCu`4sIuJ;yQs%R(HOq#GR0)DfxrOS`JXZ=V^Knnxl zd|JCw^#`r=`zcce#j$Tjbckrd#AVlRZD`F@ok~blRF1Wgc`HL+RQDY)AxIFh_e&tG)lyUS^889q) zAK9Jth;_u`zvDVWIc@+%C!u&w0_u4tqL($M0-z#RI=t%Ty=@mzh@(BM)_hHQFaLse z1_<>|Dwv9e1G~#Jsm|5Q_I5=-*)YEkjeD-)fyT!tw*Qv-!{n$eQB^W%0RnjU8X;P? zpkh+N=g3amj5sx4e>xzh9k+u#ESWcl~v7#K&N%+{W z3BztSuwYdOe5Z;CSO65NiCBKq49x8IP8$d{x3m=u)1l|kvgdz^Oo>?4QUA$PhC!;k z&VO=Gj@;lK53!+V$?lrDXfzAtB6N(sAhDSX(7+T#UuFudS~NUFwj}*eF0g0o-*Su^ zq@3T1=sSkWvZFA9WBKVUZU3n=hg@uZ&1vEW{E)3^nG7!}8p&adO!wrw){&3vyb6(L3p-Ye)nW9H?tXxsX8)k?TANs2}$(|d@fj;V@VUUr-- zyoQ8nTN{}yJ}K6!?t);^=q8_JMhbReus?Z2-z`rGT%(pkaLON%C5kQ{G0$4}!Ol(S z+j$1ZZNS?)r6%QJNTtL6xGcHpZ(J{;URznN=_)aD&Yl4%FtsP!mnd*P5P<YLp)K)jL{nG?SNeTK^4rwDG1cwmy3bvJ7S`h2yaD*NuX@|uG}LX zH^3QAhfe1EgIvkx+}=wT_S$ajGplNgr5!tsB*6NJNryRVs-ERnoK zn&&Pd_K;0A^v$Q?0et^NdI)M>D5JR>!nlP0ARDHL25aHS9kAMC zS7i3KA+_0|bEqX^Ky&Lvg3InR&G56c8PU3_mtCHHEaozc_h&_83>5m1 zNO~={25#Im-HhX52$Cu z4hkE*U(Wa!QvW<4p4UUcmt_n6XfP-{M~Cw;`Sf@Ube>-K8idVqk1MheqiD_~T(|Q8 zDOZ+{p*wIaWhcoh((u#kAT6}w z4YOfJMu1+*u96zw^()jCt4`jy6Bc7&800?A(fPvbU+rzV6&>%{8@l9K2x zGT_)tBN)JaW~cHsBKQNh5S7?SBc*3U72{Tq`2<>u)tfW)zzTqbmVACFpeFrH!a>+8 zuyx$WLqs=AYQh-iJ)%8-QBdVzc6_Lzn}e}@W>I?55iy%-Oz#1 zuO-**qk}dEaap5@BXOQ^7cGeYtRp)C5pHH$ma&MO$@mo=U7k>bm?m&BN2?~$xao6c)tqxjvy9x6biluiIHZye zB#6*q1)=wa75>bV*#+&1P*Q*N;IH-IaFF#>71_-hECqQcY$LTMiCGDy2@QE1Qj(h- z*?`Ls2en$Ba)i-@?iC*@U1nmVYQ008FFB=GpVGWCK;y3@Tq>dA!Ex@*K|`cM@qy@@ zKMf-Fy8{mjnEaDTCV0}P2mP-eZ)#p$ps2aW8%G=M>{*F^LtqM*apUbk%jkv*^%_qD z89>RHrG1?%Fp#w$$gFYM8hVA2_+0gWfG~N~{>%b=7icfo7omt;XfnuFTEDX|6f^VH zPq1r|*sa;_Es}dV`8FfIi8Vb}&1;_#b=ZwdEJ?#GMSQY{uZ62^Ku&cbRtR=9bE2N404jk90n>MZd{Tq~a_y;-36=soR@luYTk% znnTPLUk8R0d0(?GugJsHBcEP47U^>FRX8H@#Rz zZDgI=vUnP_{?uJeuFpfB+&@@l#(lh1?6$6ah7nSE1OP55EOFt*QV5+xgznRziBklA_TF4qyea*u)X#QK0p8f0003n!iVInhH&gJ8dWI>6S;9_UT_6A%W{x-=E9A#oo zQ(zZL2r3S=^Ov%@j?P>M+#{s;fwGNlwV~BF*?{Y{i!Qd}jsVSTk^!Y26c-jImas$7 zAJb#5Ls+Hai(sbeWszQ=U{`nU8vMQG$~cn&^@A~``H6lioP7y&Ivnz0Tp_JwI5>%7 zED(aMEwZrmCk@#lsPR^+s3hp9Qs6KLh-gic=**fXmJHuz=Y4D5^j4}z@5~-5{;p6m z!-SMXE4>nX#YHm~J*(R}8+78R_rADR91ip)Ze!sSn1BEP0^^=Wg)7$c!v zc2F=-i5I>}v2oC(;>@w;%jc{bw|(c<^o4!Ef5=yC9|CVGE@-8@TQ7l2V@%PFU4!qF*KBl-lsU1v`lqwZ};uh$mK2FO}f z&eP8i;NGTB_>g*2+vMAu0f|90*?TY$I7BH}wRaBs@XZVqGG`eo493fG)Gy|sDuXzy zxTz-?j2FC`uw7gJu}PU5nwlu|=-l$U4yT(KLOl1UFWSPTxwc9rI$&9;$e%B~yX>dol#N>ve{~yPM zR5su#jRGaQ$h>*xt6eROh*-(JOw1YA?^bEqD6CTSX^PZt19PE>k43XWNb>x}`p4bW zrF7lahjEY_pZnHEAp>*ybA+!vjg>El^xIPA?XXf!4Z( zm0m7*kacD6TESK_7q;h=Ei=#FS?8Kf!TosTOh?h?#hx~Ub7bRwBE{kHI`@t!u2zuS zSe5c^V~I5U2>&sEHY_};ABy9Yl`2SBC-uF&_ux&n#o%4qk~lBFqySAT{`bA$h?bX$@#^AF8`&lCWh9V6(k7J_a|Y=3_$-EiHrb&H&8@ysUF`g@ zd$SFfD+zx&l!&hqV+e*LA3H~K`?#5O5aeKNRZ-DwV!;3a0000000002i3Xuf zl+C<9)P!e9UaXrnSZ3W{G?qih#!;=IMj^~_uZy-&?XQT~jPhVCc9 zvnv(1SqFmk2s{}P00h1bz)>}G1YdMJum9lUT@Aqh}DFmOt`OhSYRXx)yKDAuItp;n3 zemgZd^AeonAU(@5l_G)V%|D=Wv3 zPg$EH{$*I6tFCY%Lajxn;>n$ zAVEfCi~FYSx>r*fvc+h`{pC>7$&9RA-|MM^Yr}3Eo+EQ>bpfd13v#K8c9%T7fK(^z z8uYVl>zAFeV`T>9SXrdCqr$at1>Yt~Dx?+h7#QFjhue9^UKiPD5)8HGAWPtix3HG; zcKyR4o$V~U`+IsK*Isi$}_7tu7QuVkBRAh`YW_l7L=N#WD8nb zy`h_TEtiwnq9?ATKg$}o0*ve2jafDAAUHUtfQr$rTs!H;^68i~fY&y*p{q|=O6f1F zkQw&JGA~lua{Dqy+u6cSt*&-qH)1*e*C0?GEA%!Vu#~b#TGS&!nTrBesaK$xpA4fO zBF`oiNqd{{>4qaUDkf3zsDEBcHr%EVf&-qrW{z}S8NJh~g_$>Q6R9X0J9^(~CBcAI z)Qh2eJkNLk77lE1J&d~YGpqDCAOHXauA;Sj>uMZUs2q&2&K@c>x4-}2pU^E>*>7}! z8DKF>y2yoJ!Ulpd3L+bezH=HMi@f=40ZxXUjqYm~?{5}d&7SrU_w5b*71 zr62%pe7@D#lwKRPNOXTT)!IZJuoTPy00000009vyeg~X1_z^`twyGxf^)$l48xrZf z;3uYsVZyS?OF3Xctn~M`f$cNQI$+yN=15YAJ$Y+ic0%cgm zm+{q*s9d~ufAkVYKWoAk=+hhQKPBi7%q)tILrdce>9iV{r5ycqtyuObDbk`B{k`vp z4~&C<>Co`e=)5M_E(0CO6RArP>Im8k4oEGZlf+#W2<;K{PN)~u9J3qdS**CLbY1ly zfw(wiuqN#Gg1mfl+^=BnKmY;hS&(Bdr2B(%Cow48lm&A|xLExgUSHbf zJON$->*H=s75afx&?Cwgu@J5BVNME{Xj2mfNJL>@e^ew&cvS_*j?3gR=oLKn)A+uK z{%d59cIYqiRs&(T_4a6Q8?=2$;hRm%JyvDjNM#_burDB?lR#2)8SoyyBr<7fYRW@V zG&}+(rwa}uBmy*fqA-$2kll{K!S~3t7MU0gy03wVSNCbqhXQYTp&6pl4Pq^%$_p_< zfWevcPXE6NZab?F5R98EG-r3bk#RCNqli-2Z0XCyk|On)QYZRnR;0$QiGrZX_Bb%r z!bC4=hH9dIw?(W{bhx)r1bu=nFefQ`q9cgpGoAH0{b@T@po*4t>xn$Zr`OM7YNuor z=-4Se`Hl0Kh+T;TcWBqBh>0QgA>MIwvZ_XH{LAG}03lx03dwAaRQaLrNelThP1z*y zKt0+Vr*Pr*{7dpXG#VuVDEKVOLS%S!9P3r&E=`*%# z);22tclgz#D`^y$?tD*d_mU)%y}YZdfB zqSkv;-6BOg{E_s~J=i=_l*(LeR}n7*oQ0HLwcGiZ|9)_3ubWx_f1gnk<-DgHt2*<` zSDC)O-<~4QS11(0z#Fpv;%-ita9O8Wf|q9M8v#njI)v@%YeodA_}b!@gAR-VA7YB%*(3Z9)Yl5{bj83OhxlCY7tA3`d;M? zSJ)NHHmpe||24f{+eggXI)WWHI5(y{CH35l62JYKBFhkDp1>JnG_*O4qBJ(~EA_2W zSl`7$z8UM2-6oM2kO?B;z%gJk1eCR`rP54M0%0piH^Y0h4W+*d^4rH-$|Lo*fiIbRjcens<>sCzal zd)y9!MI{9`}?s8r-!vXyi}ME62Ds26l8M@QSG;TUHYmQo8WDg2|F4}fN$M;*4Mxc_HjTEes!sz;}e$a zLOSt$@m@<(YMqafR&sZUOv`;1;fC0EG3Pv(BwNuX#I%l0y58YgEmBjyH~Vb{m1SsJ z0atfp2^zKPit4U&Zrdi6gOXtVO&;U$fX7!XS4oZFBE<7K5nLu+EE_I+9oUYgJf!up zDxJ4&uCUBESH&Gt>}9PiUF>xT z{G(SUE+Bt*uVS>z3&MSU+)WnvEH|7nIwSXA7B!VCZ+&F6+cPkscSlN0ROHc}xYH6F zX%GA`XP|u-ofGex^4WLgRNW`vbYx^`mn4lZ{J3{1C=6N=gj_oIi3U&_2ZI@)buDdk z7w73)j_+2wxuTSIX*F5g*d2AfjQN&N@E!2boU%u$S~PXir>>yBuhRavKpl60F%u2rg1u}r<@x-P}dT;bvhg%Cstf8^Jpxt^oeKavU@LnyL}!hPDC?^ zvM@}E5>nPiKmY(UT^R;#VzPUFMVs*Hzg*2#z)RB=wT@m(Ja{z;LdBCZ4=<%t&we zCwNz`U0@x%e)l^u4WtV_Rld}hs;s}~dwP0Yazdq4I-qO@tH6nq_80sJFAZOa#8TJ8 zTit}clR1>%jd<}*!4IaAl*6Tqls=%KN8W-D7Xl3j1}HkA7OJKrG_&7(u7^?G0M{6Nfew-% zu(MKPtR85=#zURM6F6l%Y0-anWc7MQuq$nPTTz0K+{-`J&55W7@pTU?X~MvQ^Yj1B zcy$w8xru@Z^DdjzYw->LC;CdCPMpbP7EsLG3a}RBo^9&)_gc;W@x#k|n-~SeFc&Q8`uqvuaWa%DJ z7!Y|p6T|&WW3&p{rqfrIMOuyq^^~t41XSys^&G{8>OM+OhMD7A*NMA@XR`}{vYr<{ zA-J~XfQ*>51IO{be){8tb&{fvao58j{_BXOMcnFwG@S>E-!eB^yjsI^C99S8pS$4P zQO8YyNW-V_M!r$+6??v&irPSHN<}1-1~-5s<|D za~62uFv}P#u9WWm)Jeh}?1!yCc;nl5Zk;^CoB}4}nnmXsU?|vYuw(eRuz8@fr7GD5 zbw-M`W4*P#wuxO;Rnt7ykQ5yW8PR0Kn@MmECA=52lM+-`HLlkl(al18N0deVPA)pm z+~{XgUW;^g2T`UN4U-DgZ?eP){XRV8r7&J?Wee&8G>bB0rFzg8fK1d^sD;&VE(&3o zq$|o*P}lv4_kONGdJOIGQeQMz8#w+Ed&^^njLLKBSrOtxDS?(i*=RCdU1QDiT0U!4 zHOnJ&>2wgQT|Uu${U3Y{+A=m0+}aXEIGEFVpnvT)cK@Mq@b%j};ptSvW&58ho9EP_ zv~bs#)^oX3G|f@~ZA#~VP_vg*O> znZ@Yv(T6aF7{e*EM^ISQhm0x5bLJXBXQfXpD%g$IeQs|BTP@H5Is{FNO5#EpjGbjk zg)NcYdi43^DsZam`n^`c05*#Y@J0zUXQ~*z1*L=~IS&O`& zuPV2!TlO=UCf?5pY`B)M{p-rQe)ts^rVcMk3G_7s^!|etg|8@zrSGWk0CUj779BkW zy+X>NWkk?WnG+R)%iy%_YI_xW>0vkv2UCaGh^P17mhD|m4rkXKZ1(%24dr{?cqwD8 zt|eQtp3wy;Y0*fjv;#LoW(ZWV-_e6JwgHXL+d^#%e>L}H2~ZbV?fK4NR3)nG=f6at zNmZLyFn$lr; z4!CZ4J1_|f`k8oV!Fc$-m zsOX}Z3Wp*j)2+gN+4+6X-GT%BCV;Mb#)TQmQE2QrIQ8K1Jb6`=KpaIos+9x3Fe=tfoEE?MK6ELHyu z4VO$r*&<(Q3}DPWAhP;+OChtK?!Z(8m9d&_>&vKy_KB{HG?I0CH?+QOf4ImINo}^B zilAF`BC;mki3;Fvbi5>=KA2T!!7TsGUb-}?+h6nhp zWi3giY4W+555$5z+M8Z;DC&K8+Fd(&d%S}!wT?%8jK>q&(uuX^L7b8# z-@n@eF|AV0j6AV)u>JXXYJ5$dwLA$%>Yebl%R9Xipk_x{^7Y3fW{9d{d^S*b3l6S9 z;+{%wgjQJO)+gALT(YW_&%`n6H>Ra===hmX3fjq{$8(ZYLp#U$FG)IeAJ{!JK0lthO!3sdNNws5c{A_$Z-1B6U!IFk6%DziW!fR?CNeZHScua;{0&C z=>Q)=ng9Vv)#C(Qz3SlQvad`12AickN!ToNL%vykhxHu7jyO0SyU?0+fSY1Q(fW=2 z*SI`I_l}I&v?e{8$tsl~M7+yMVF}edX|=+TlQZV3-0~D9WlWtWmLLJB^GS|d36`MS zIRS=sD+FC3W;9+m!*ePU22tsjrQg+=3!4Z$q`p;~+PC)i-7-B;iw;j2($np^wr9^i zTIOO8^J%^~wSpZ7(-Ts|G2(_H@+?_(2V;d0Aw zQlvcL3U!eKdZ?kN02ZNyPi8V%=>+?y?7h(=p@*1})Cq^cnMq(^Fz*MZ-OR+2W~9a7 zTIezw@KnL{7^BhxrvE7G=5LiQ6M9$FFL(0pNoV?}&1N>RkqzMvlY%Xa!@A_C1N5*1 zc<&ZDtiEZc`fHj);5vwfspZf~H71*raXjrIGN4^xLpzDHFWZCqT~=a>FmH|lF|86~ zFNKWlo!ak{+&dQ)Mbruo3#Bq&DX?oa!Gb8!po{;X;CFj92S4j7a2(m%cLza*F7El! z)C4>SPOYO|SG%$E9ekYe!4FZ~eg-Ze<6 z7Zdm9fW)EJxiJ&qsSYahGSa9nE4@D3g^<^5b6ic3g6qY`AqyI8mtF4Z@N#k&d}?w$ zvf?=rj$psF0Oci}4|C}`cpy2hZNB+muHt!dCsy@3GoeSKNbv5gF+8{kzL9WFeyrpSWO|S*aQ}}6K?PH9_yDgQFcVuFt5eM) zpq*6?l^ny&C6geKrh=d)&Xcxf)QE`+-iO*R>To{PrC}1h5^pc^0`4U@u8hJKbI0$x zc`wuR#CgHDj#$TB7%A5LKYhHmH#P@pIsSnc)5GUVO>nNFw(*BKA|+`Z4Y>$6r7cJZxG8K4 zb+i}m?y%Luc!Hi*FUAw$<&=Pi$T4^J6d@WmO^&s-_3!4sl$Aet++O*o38W9<0Z#50 zt)G6dT9+xhEP2!ljeu~i#(`?Z-su%qDd}E*d40>l4W(^2YMD||7G131KT1kz`P4zT zyMfy^(Bx89kv|NQB=3Gtvrzo)M|gfoX9I&}!E=b{*eF>RyN5gfP z>p9aYI6$dsR^FO5h?|!_fO1>%Rj(74St}NPFoexCgxY$V6>_3?X)Hy36P=Hbbw>DncCT%GRYZc zl%kwFxg>Vo^wf$hPE3|Djmcd5rwX-F_<}a#nt& zz|7SIoY|!DoYn9{Q|5&h-5F4HOf5q7OinPkdZjfnqVB) zqmZJuFBn5H-=&1sLxq3fS)unRiH|lkzC9yIAn4sGxc`Z(e7)ddp-;yjX=F@?&DooQ z8rCf%x<5eq3L;8)MuRK-%sw+3iWd^nrn8i5Jf8}oLEr#xVfj>&7#*82>sxHJ&%(RV zf9r=@uSs+T#VE;fD^*4=P1 z!g@}*IaP(WRvv+C{zxL>)9<97Oz;8V3_LS;!w(a2{>8X)6s_A~*hMiI-B%{oId73fITva%(Orgtyldc)mvycQ7sfnBv*&z?U~hnn@C1pD zdqrtaxRfR;;c&bp5iv&-T6GgpNYZ=S-yI@;hc{M|y%c3D{`SHjy&xH7Fi@=w{tlem zxIDf5Uy-UmSl|m;OH1M~Djg7OVO!KJFFgE@c9hdj-oT6^i?{4aeb1|t7acAHu+`xz zw7unNobq6J3hoe3hKHFn-eAi3_yi^yAr7<(>6g#@dFgw4=}xrX3o`{;yLfbJZg53kd-Cp2Y~xq1?MpPps4W zmB3oDxq`~QyW7H)_8wbpEPL2v6+s7QgWD9*TbP~;s^AE4vi3hoHYpZJ1JH1Wczf^M z9R*@ND@!CAvn#^&+-|zhguhbz)TKDRm@gLjDJPjDX;;U!W6U^XS$Ryw3i71+1;DS4 zx^7TqyqeM;d}Nmc4$jK!<*wHDMmhi6wnyLV;p}tA1+T~mv2SfWQX&35qCtpd6cEhl za0%#sziUx#c_jsKBm5JJSUJ->S5!Y@%?Eh(9O21za>8Xsqw~{5!XAxnQQDljRtz7a zq82XoXmhZjs^8G3i+fFH@j}V=Gopc*aDc>wJ`@eXqXpTQdzGwvT9gT%yt`3POYpj~ z79z$U|Bk=_06fUy9rITksa5bGS@O1iDmPy|w*I`WT(UvjqW$zScOsq`kcn%e-?9*| zrk1Tv8N7*qb1dTic)zYN1nWsjo1uhiZ&{q=ktMfuXMLC_BA^WMUJp@$mD0S1EdxiR zmn>n{|ACFz^zdLtXVIr1rN;_?`b$A;3r`Qe5UJa{-s*=4Tg;T`s?^D|sUYYI$^xQ_ zX~06Cdh=Sb!57TWQkwuBb+&5>u>rc2DR=IV!c>oES)*K;!`#kq5|6yFN!kjgOkR9$ z1Mihdbfa0xp@YLO8+iir3=W69koS32h!Q}U&ScQI?F}JDU$X;Mb%{7#~L`f_he@q))lKE?5%cqb4&=faYN zFeV49Z?|$K_H=IpmT}F+?`Wdw;r^Zh%x7FfmVZKBH%4zMi2=v)o7MCzb0Y}0olfu| zFt#GQ#&_-csml+!9=i6i{WjD>^2Z=l0~$1S6dH$Xr$gZi6nD{tRu@UbC?2D7EeIG` zI0#_i>s1VkAH4(^kfr*nF{jCrb1tNs5?TJ}2~OgFoG1SEKv~2och2M^Cz^gF@~$#S zAwgj=yH7YVYhMZ3{NTa0SMAWh$i(u{-)ubr`tFq)w;u8I;+)JUFSM|pVeGkfH{WJ zVL$5)`Qh_4n$KTy;?yn0$X#NjWps(rZgh$=fNIYt=TXg6CzMArV8v5-IoqY=3`1U# z&gI+7^D6<_Vx+!zRH<>#HmRWvK;65<2a;v&QRUK_!OiLTh$>ihkE0`F#EzAI-9R49 z3VyZB7g(x378_h|RqhdvbmF>Fof8JHhgA`4>m$&rv(N(XAY#XHAGh5`Ve8BTz|Aid z>0Mi^_~oI$C$Afa>tsF!gjWyLg5sF5X7$x@n4h;@Qht{QHx;mrYy~tcU!9yoDV48e zJmds-(`snp=O~3qqe7I~Nad2>j1F^8#MT)#D*NL*Xj^~Rk6lX7XOt51EESa1>Zdbc zAJZAi&E2+9AWmn{BL%ogP6)V%l;&5LU{KB~^0~|*&lNJ#d+ z{taAJO&(3cJ6nPE07VM-;=kCwK~@F*O~Q)TXD<7S`A6|7bJa6?*#vz~H@D5f7>{`j zE$c1Xc<2BZZ#V5x-03GA)&b@ybu7|&yrie##_R+KQ`cOhi+2}tIm`9dhW%#(%BPDqEMWm^PsWO{SlrjW)`uY*M3%x8+wUmmf; zvAS$ud$w!x3h|TOjD58M7!(rV@|w!Ru`d@i-UeS03n$^)%SuL9q1qpcK-W_POK4L1 z2a$1K4UcBaF`0>ksisMtu6_HY-)k1>9RQhA$UF!}@Cj`8;Rz!(3;rH*7FYE1IvRcf z&w?<+)l3fs$U9+Kq%>;0*ReGb;GaCkZs$sTqYu7vfx111yc)FOOeMJW^} zh)VP5smR;qSZ;bTr=E|t34f)sc)>ambBxQ8-(by(UHR;YyA6{7{+P~IZtb#(0tAC1 z_Jbm}{CUC^3tXaAAyI`D&n-%Z=8)n~R?h=R=x9R6BV~G7Bt9xGsz6d?WP70nZ>N$m z&#Cd|_UH#uJKqjvTKM|q^P1F?Db0vgNCm-3$5Md}N;cqrIMrr9fxQlenSBM;#FkNf zRs?FP0MhdL<;sS~4idtM^AK5-l9=fqG;c^nf!}BDGXtDR@+XjPMVuiRei^m@T0u!d z8Od8;ot3FHY7B)Dr!Hb=PHU~I{e|!=EKQ^gjcL}4cY-E{>(h{E0c6b79Uq!X?_TYG z^WHYpgJFGyS$DN;d?m+Pe%PfD{3}vvG3k+6!bg-t_esdxmrmkjoDJ_i2b032f zy`L1V&={^cjb2)LHxeKz%|McGz{z+25aUw{>ig4-(0N9Dq7Kd^!z6BZGnD8Zwp#+mSrjw(mz=W zwu0UiqQ)N+H)^1gEFCv5mhVDcM1F*OaWS>C6?TUKLQCqV{8H%>=ES&!LG|aI`ldXO z?!|Fv+XFQ}t?y1ic#}j;bkH8m_D&u-rGID?al{Ge*+&Ce%BDF_Yc3FM35ZSw;n{$oOwdcA)M0~p ze>&8kRTMB2P;WGC?8bwgJ$JkSO;Gq8a&zY=kuiQwWA|Z64O19g6j~5nI9kQ-XKq}D zb+yP+xO0qA6G4OZW0^QjK;@!kf#oK}XJf=iclE+U+fQt;K@L*{Ubx5@mK^|7a4)!q zw6wHHp5(*wX}HB=S$l_j(`)NnR_`<~5MaZUaO0BTPnmZDJ*=6Z6YqRrGcoq^u>5Z2 zpcxj6KHT8?YdJZ53##s~sNfarXH6f<>2fDF7^vF+_U5H%?3cj85A`$~-XfTV9>;@5 zc8yV^D%=f-;sbM^xr8L8q5v6aF5rbanUi{6pF(6N_%|0MT)beqqi~hK!v4Q-2^DIS zJ6EXxNMR8tuMkO84@Q5!XTFy11#D@~fy$T59hdX^X;b@*%8buLP4eM5#ng90v{1(+ zRejOmFqQ_ZhCv68;x=sN-=5iNtdS@2t8IG&r7ttW=K{`lW+5AOGc%j7y-p;rM)&H9 zxg3Rvv@pl81JhpG{Jo8?@*I+(Pf{- z(^l~S00000000000000000000000000000000000fHK3l#{D+BKdbPDAx*Gcca1vO Ujs&;Ufu;b;KI{Uqkp=(&05Uz_SO5S3 literal 0 HcmV?d00001 diff --git a/products/connect/get-started.md b/products/connect/get-started.md index 30404ce4c..9d1386f7c 100644 --- a/products/connect/get-started.md +++ b/products/connect/get-started.md @@ -1 +1,76 @@ -TODO \ No newline at end of file +--- +title: Get Started with Connect +description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +categories: Connect, Transfer +--- + +# Get Started with Connect + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + +- (Optional) To test a transfer from your demo app, you'll need: + + - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} + - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) + +## Install and Setup Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-basic-connect.git + cd demo-basic-connect + ``` + +2. Install the dependencies: + + ```bash + npm install + ``` + +3. Start the application: + + ```bash + npm start + ``` + +4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: + + ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) + +## Configure Connect + +Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: + +```typescript title="App.tsx" +--8<-- 'code/products/connect/configuration/get-started/App.tsx' +``` + +The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: + +- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` +- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains +- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI +- **Defines the theme** - this example sets the mode to `dark` and adds a primary color + +## Interact with Connect + +Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. + +## Next Steps + +For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. + +For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. + + From ba6c0da2765446138d8c9979d286bd24c0839e2c Mon Sep 17 00:00:00 2001 From: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Date: Thu, 15 May 2025 20:09:46 -0400 Subject: [PATCH 12/55] Messaging - Get Started (#381) * wip messaging get started * wip it, wip it good! * updates guide to complete steps, add terminal elements, and image * adds TODOs to update with final repo addy when avail * updates per feedback review and some resolved TODO items * updates to use --privatekey option for Foundry keystore * Apply suggestions from code review Co-authored-by: Erin Shaben Co-authored-by: Martin Hofmann * Update products/messaging/get-started.md Co-authored-by: Martin Hofmann --------- Co-authored-by: Erin Shaben Co-authored-by: Martin Hofmann --- .../get-started/terminal-output-01.html | 8 + .../get-started/terminal-output-02.html | 12 ++ .../get-started/terminal-output-03.html | 6 + .../get-started/terminal-output-04.html | 7 + .../get-started/terminal-output-05.html | 9 ++ .../get-started/messaging-get-started01.webp | Bin 0 -> 158478 bytes products/messaging/get-started.md | 150 +++++++++++++++++- 7 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/products/messaging/get-started/terminal-output-01.html create mode 100644 .snippets/code/products/messaging/get-started/terminal-output-02.html create mode 100644 .snippets/code/products/messaging/get-started/terminal-output-03.html create mode 100644 .snippets/code/products/messaging/get-started/terminal-output-04.html create mode 100644 .snippets/code/products/messaging/get-started/terminal-output-05.html create mode 100644 images/products/messaging/get-started/messaging-get-started01.webp diff --git a/.snippets/code/products/messaging/get-started/terminal-output-01.html b/.snippets/code/products/messaging/get-started/terminal-output-01.html new file mode 100644 index 000000000..cbdfc5da8 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal-output-01.html @@ -0,0 +1,8 @@ +
+ forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s + Compiler run successful! + +
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-02.html b/.snippets/code/products/messaging/get-started/terminal-output-02.html new file mode 100644 index 000000000..35f37fa11 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal-output-02.html @@ -0,0 +1,12 @@ +
+ forge test + [⠊] Compiling... + No files changed, compilation skipped + Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest + [PASS] testDeployment() (gas: 13544) + [PASS] testReceiveMessage() (gas: 22579) + [PASS] testSendMessage() (gas: 22719) + Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) + Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) + +
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-03.html b/.snippets/code/products/messaging/get-started/terminal-output-03.html new file mode 100644 index 000000000..8060464a6 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal-output-03.html @@ -0,0 +1,6 @@ +
+ npm run deploy:sender + Enter keystore password: XXXXXXXXXXXX + MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 + +
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-04.html b/.snippets/code/products/messaging/get-started/terminal-output-04.html new file mode 100644 index 000000000..cfccf1763 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal-output-04.html @@ -0,0 +1,7 @@ +
+ npm run deploy:receiver + Enter keystore password: XXXXXXXXXXXX + MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 + Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) + +
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-05.html b/.snippets/code/products/messaging/get-started/terminal-output-05.html new file mode 100644 index 000000000..1b2802c58 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal-output-05.html @@ -0,0 +1,9 @@ +
+ npm run send:message + Enter keystore password: XXXXXXXXXXXX + Transaction sent, waiting for confirmation... + ... + Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 + You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET + +
\ No newline at end of file diff --git a/images/products/messaging/get-started/messaging-get-started01.webp b/images/products/messaging/get-started/messaging-get-started01.webp new file mode 100644 index 0000000000000000000000000000000000000000..96435c3021f591a7c5f77aaf3cc2f0977407aa1a GIT binary patch literal 158478 zcmce-1yr5M(k_fk&;Wtp1a}GU!5xCTySux)6B69ro#5{7?(Xie|Hzp$$;_E^?|1KA zKdaZ;&Aa=pw(6>Fd!fxqMSxR z%!T5`(IVio-k9V*w%@e08iBmt%Tw&7sHCFj=z7Bk*Zuinb~EjnWAw7_`F46wuP>_| z0I;WG&FcfrNsCGYxCt33ycoVPZ$Soej2@LO0TQ2!0dD|`PiX_5nCCc8jt6PWmN%Ym znuCD(yY{WoKET?=%+BZy_YS}e(BXLq2)`YC34A)e)~o}NdR71`05$j1SCG%_53_ft z$E(||^PbUw)?3h*$Y+{cuCvxI&nZCnqwyKS1LSq<756g00^sJk=fVE%)#jJF7tiOi zc)%R@kmou;>ZS7qFot$Pvk&0bbnv`ty?RUlcmV7HfiKK$nwP7`t*6{Ho}Mq8p2vVS zfac5KOW7%4Bkz{`cJ;1 zA*@Kbz9f5+0)QW+pGh7yZ$@X(w|%g58M z(?i^#v>MGdcSSd}lhqk+B=^A=+^f7T&3W!lPsW$B7u+Y3Rn1lIGJxC5{xi*^;yv!! z%k~r9v+LRAli|JPxu#ZYfG6CG$aCP6jGz2uh zxSspo&>XiebN75(U0{IW6QCQ=&s_kpegV8_K9SsNK6&l|J^%s%Z(l;6L!YE>rH)o_ zJSW`C-IrgUJ*S?^9+qERFBWeBFM)frX9zo<#c8#;t*tl65uYw8NeCDrX?H1I(n{@? zqXu`)Is`Ni^DLyq_1b7qNKjvwOec=?O|TAUblGT+Jz6ZK}Of45T&%hSQ{VPUf|TO_u$< zC!T?Puh%zrBwIt6YqMLQZjDEA(N4Tcp7D0})BU$H_!*2-U5CCZEkfr3<{aEjl92BO zKS3VXm(!ttVq{(A<8r&c{>JFk9p0m(WL(;I+zdWpG*J*V?E|q7RI6)&m{(j#by)xv z|EzzUVRK5MdDxUSQjevJ=+=B7w9q&{ZF=j&Hs`ps)9I|jXpC%UZ0TON@Q9Y@G_o%G zGN;k;i&4jZUXQ>dq790Zx2e|N?6irDD&&Z;J(bVRWEP=)()M62sQUd54y#4D>)S$x zXlk@dTYcEmcN<@jZE<_isbP(i7>JcHQ8{jtcg}CG`Q0FAXai=K!;w*aU57yNREZ@8 zQmow>@_Y{-rGc>9qe{?XWG%+4mKA56vogu*3+jyKPl^tkhAc2$D#Tgte|=r12LViT&bj{`r;#yAlqw)q2Ep0z~cb7~{tnk~C@ zUSP+VOGlDQfu2&Z9|^~6nv)dT_#Bot)GGtnZy&a!c@3Vr+|g8FBs@eRwD9OWWCDXu zJsgIFiE{MV-w7fOjl7FdS|WnDt0t0DSvkcjoG9siDNct=uOeH`=ds9oUWLzojK{bd z%{KcHsJ?7F*>&%53|1 znBOpMzKp#=<+j&U--!sy-N;?eGHfU-y%ge?wU$-?jDRZW3f^eHn(T1c%5psGVZB)T zv{|Qq-)qr$8L{lRi`{TK!v6pJ*F9go5&k}4i2$Pu-##KYAMIA2>P0#s*Bj$NWf`2o9Pi+L`BG<1w)szBH-+x z5b34El;EC*%^U@?MY6PeCP7N?Mv&e=9P*7-Y6~88|M+gl4|VZ<(W;2}xmv&LQQ~%H zs|2`*s_xqHt!9jO*vup#%1PO>_`-fIce^4FfOl58s=RgBE-|Pp^}@5R-%`~->ys4U zllJ7>G3ag>TL#Wd70!JR=^y_vN}}<~LKVaF0s)5VI#sd>WvP|{u!V!FddQLDME2Fp z7|_Q-SvTX%b|z~x_kY~YMa{~a>%Sg^@o{8!%cL}>rl`HO%ev8G?GvhFzEF0@k4qFj zl7KRVZd+B>AYCNo-t4IL04$!pFn9qX1@-u)`#WA(5ks69lhQ#8x2JaygjJCujEeeo zTpozN-&-dZRW7D+L-7PtZca$Z&zp~?`QdfNTkjJW9@XxSb|C7Av0TNxqGH?}sk`9mH>4TrEPMD`a&V6(BDq{h6T}w*NADwEE|s$AIuwvY zxLz==@+GBSF&n^ucpLVYk82R4gw=5tSVlj@Y`;_r@fl-6ui71d4!dkD1Qk5CM$jyiBQD*XRa*my~_v~QT zst_|Q{4WcUm==2-kwK5FaJD&cI&x}lY{Ya}kU-X5F<0hmdPep2^33mT%m^pp(B~oCRl@+qoFav_)25G-=h{Q=;nwTU zbuQirkyeq$8JjEY3=v7KOQiMWS|Ju>s|!rl*l$SZP%PReKeeTC;?LW;){p4fY3kh! zu&wW!^6OW61O(`j07ts3$t_l!-O69D8102vkee?sxfVX0GT42$$H&M#>~Erw6BvRK zmFE||2>qAAt7JCa2ZU%rTy;6Z20AnqSzl{w~Bc@@(- zez3q4w?OEr$nM!xe++zvfsn#5NB&!ZKgjl`UrHW`-Eqhs3|&MMZ)HkbCs|%t!%{UV zQV5sG@r>2HEy>XxiAlOh=B1v}^IL3dA~;v9LM171dgWD!eP-EIX^lf|M)Y0@IY0wn zEclp#edClWz9!C_Hu#l~F#0|o80e;to2m+qZuSI*!zgBgq%&zsD z(nf(c6HfmZ>&s~(W7kD%=~`UL)T+k<8Hj@LBAe)kKcs?qr?tA`A3bnCVPORVb)Pqs z`ppVZ^k|BWb)LYe$+TaC$KVTmTJZx`q&2q8=P~%&r3gk!sI0#C;f+mvKt3<;LZ&1* zCfoVj3*)Y1jNR92i0RS#ju}AmLl~+Dh{~nbZ`xl$qbj-}f~&RXv}AxM{=aJSZn>zA zkQim4&Wq^FIYO^P=~C1ebsaDSvlwmhA}0{#NW>>cljA;Ew=IJI=O6Ag5e(3d6GKix zIrsy|>G8TqC`q8xg96&MIG#!tHu_R-y@bI@7TaGP1nu$k&T zeLglOM-To@MiRe#)6>3@_u9>l zG{@j6LcJJgk6Aay0KX@3!Vo5R@FfXn3jSY~R1O@KtNYlBK>82T=vv$%l2EwWv1l!y zL^?8k8T}9N)j?ffpXo1CI^pOg6Ep7;ceh6R6P%j7C6mmCrYun1X-llQj`X!4_-NCw zam`VQ@lI3pl4kzs5)&)EW`?{oUmRR}#8FOL#=ThvsDwd(wj_`T04>Q9Uh0^rGtchV zz1HI+RcH}Yt>A-UWW5Gn+$$`ZTXl(eP0hLgG4wT`k|H%47h4jWQt(^ZVLp|-TTk-X z&Xo|Bdk7~V8NevEqw(88BueL8uZi)FuI0(aWBgpkkw(CmLOOTCRa4>3*+MxbUX?y& zyA$nPQ(>HM@X)Dss8|@gU7}Jrz{A0Wu`^FcU_`RTn9yu}nGQG}i`Mk8-7wq zl0$gvK}+K>_G^i5iAKTEzr*)$@y726`bQ-84S-UE+Wmke>@>=zlRN*>?*H8r{N)Ke zWmzZi?&k`<;z+3k4&!PWGOdf*pJwiV1MmC}h-Nh!i94H{Bx=(iaAy4YRK|XoWn<*0 z_3xAZCS3e~T!QXdS7dzN0kHAheh6`XvHCu|_h*7$`UhXOre z@QSeCn7HqMD4%|?1vJvYT~SmbEWq{g4)2B0bcVaCDq=n~qFNB8gvEf*RT)Ej$Juuk zt+*OrMTYD!c(jmeeu6K z<|i(FZF{vc$>7g+Ed_ab;L_S{F=GGAPF5u#JgYjR#RTP8eJ4=pdwmBr(%u_``(s)T zSBb(@@10N^%c;H1fv*g84c`Uma#nQv6N5N1EyjOk?6vx8>+-$%zg@RCwobqfQ4=0n zUs4h!%zGQP{f~(5Q=fSW6+Cfhbew%|LJoJPjb&|?Q^5+se^Yi;m^1po3A?P^J@@om zH{2xQlo>{jNvhj-@!2$4{uzj^%ey4B?}jE^08qIiijv^r_4|=#b^tmX+dsLVQ306* zyG+DS-|caT0Ofa!8xBv02kRn|h@F}CyPkhLbReMFyp?niveoFntF?}IXU3;fGCuf) z(Y?O{5_32Gr=L0m0rcbClDe0XyUV{!k?#NXWQf(`oj(^XqW$$)qo_NIN;u=nl3iIJAd_}Z=YJF5#XkS-Tm}ZWvCjc>rR9V#d~-BCN&G*H6ed1Fbh##Xpozy2EmfMOu91oC zyD>Nf7HzIB`r?Xb)O~PncoA60S1iBmq%Wo;=x9z4a1FYdMT|0w9LS?l?+?`UbHMDv zKe|W(7W>{wbAIDT`@(XLIU|GTbT?;V-^n6Kk>F6RUnWOPY28}BddO5s1rqwcA`yNo zD|n^E#s2bnh;ag&_=5><HTZq_xjpz4V(mqd6$R|;)!G+yBXIJ*d1YR? z8TP_YBWbLymK0fQ9Ts{4pOxN^!%9hPUC&NIwBr9Fk15!p&7_Snj`$*ilYW7WV4$Hrf%^$cowF9~Q=kPU01~nH9dG11T zO+Aj4%}#3MqC|Acon)h>H+x?#^AlygL30IDg!|PO22Wt1D2K}6+a(5lbdoZJbP^_f zjC?r6MQKe($v54z39 zBN*~_$mG!kCtgT>vM<&HA`8z=Z%R&F-()m46k+}b27 z&ghOh%#)~^S2-bKP{ikN8ZZ8FJ>!RV{96%wk^~5<@}C4`8I?UPKEN}WkUTp5oa=5p zZ}44fz)jMxv-!RxV+4Byw;haLNwI%%jAl>plv*?=PvY~xpWJG3KJh&E^IFiKf`N&> z$Tbb*QW)$=Bi`sg=i1>0T?{evgMTV_WIW34s$0Yl6D@B1GbH{?bRi_cdnrGslt5c2 z+?{>f6PbP3aQm;|`7bTMu|RkMX=MuHW5`*LcWU-LN><#_IV$4aCDvk)Q>enh|98;= zj@6JPd5TWvn$lFgw6Ix`bE?Mu{2i*)HfKtt21LPV*85Zyro2 zG6Ps-kOu!sGyOT&sp=%Bp6%H{(9_Pyja|w|f0hz5K9%5@iGP|R%A8^J75OZ`U79!c zT>7~DTnM}}f#hd^mA-(){?J$L%VT8Zotl4O!9>ob=|ia<9<+;zfR89YcmRHoUR3oe z&geLsKjBmJgl}(YAiTn4hHI#W&Vb}3QtMAo*rHNV1zyBBtmc6%W@ClAD}0vm9}bR z!xw*|Ic=A2{?5Q}WFF(=GbN3!vQM8m%TMxz#iNS?PVIGX=pV!%XNltVYN}wVjwm$Y z4Yq;{WO@a)NGBHCKH&q@Jiw0`UAI2}oyqU?^M8bc-%0o%)X5@lMT2f(yLY6i3PQ<# z+u2Xrn(xe_uUve;Aw!YXdVUHwV$CZL(@Gz584j(kN#)LGKXkt$22kjHFe_kT_i3@! z2p)(UV+r*^kWcD(T(_bc@+NuJ4d$-A^U~vrmsqX3cl_N(TmalK$h66rs+>goBworP z(+JTNm|<6tECPw-DmA^AMm6H6WG=m_&pUgR6|Pt;l=r1mw-_B>M$$Imd<;lu{+p)%@9Xpj#Y9L26SU`9_7ja; z2AXoj9Yd`2z(^-`$kX=fXcZ@n@^@!c9=HVvpsZc;Opv5RB&cTtf7yC}_!`J4`O6{K zDUe7Y2GGm>b;{n9T=sb4hx(U;2>Zx+s9Wv@RaPONt&h6zv-IBMYfqEV_wqFnRL&~0 zSHT?i+)<~VN9>Hh&mB$l+csjNHq7C`YrTbDu@_0jc*QMKd6=5^j3coY7aeTDQ*KP1 zi`K(4fY230v!6U3y3L26X}%oZA>Dmt1YUY4LP_E!`>=)lKMp3us6h_CU+jDfCyL%h z#K~CE=izuDijjkmrpe<7cV%KC{a~R}^K-0+>~NB#Nre*gG+Uiw-h5i?By*mNJsb}O zby7R@3@mlL;>&Yb5Yk>37^%B++4bb7VgC>?627hnw{BbVg41`>ui>6*{u>1U=fFqJ zdovB{=cP;R)CUNLE7_l%H#qKSMz`nvqwZGm|29AVr{Vg$>HW_HeCma|yuwCG4W)-U zTdyhTpN**BzRqAiT>VMI3#(Vh5z8w66{G!)d;3eo_2XZ|uwDb@s%{7m~S($QG%Bm}l+$4K@Ga{{M3*ny_p2M)%~8dj?t- zp7|ZrRI%+#D@gP9jDFQ@;wtMi9d8PXr(2dlohNEu1SqNrO><(C4_Ul<3I$ z;AO%t6X%4VthXJcTT8un#I)9-1-SS;Zm5FzNGDf(%8(u!dh4hTVswL+GEy`!z&3z`mqOX1BSF>mT z6+tDorCnQ*YOD2(?-8w8liSEnoe$YjQc0V$Euuh)4x>YE2|33y(eWuU(LOw^h$cpu z23&R&{mqD!;D$+@6nt)t8hd0|%`Oip#w&7O)QMqHR1PVQ8Bz(A5bG|LGqA3Gq<65P zix=H1`4ni<=98u{fgX?pG;PL~-88BX`dPwXtcpd4)UfQ2aVAd;MYOMgq`#K%()+A3 z-7iu<2ZdPr&b^HTBPEYLRxYqnB^s)#3GnZVPc zt~Xx2Nsw?AEdN&NZkFL6gZ8SmZtln(Y~o=c-(j=Tv2QWp1hLi+_yjxr3Wa0_#!KRg z?JNad11E7&LSAJIniblkb7G^F3d>5Efs@p|hq-)}q>|;-5F@G7AymGZh`A_+gPdPL z=J$w%X?XIoifl&jCklinYx_|FTb%Ku4E|f-^=lCJkM(z$sRk@R#o@aA{1p3InwlAC z-qLsrJ{xoQ6sZAm`1-T>af8(l=Ah2B~(8`>=o+UhASO;F6zLDG({KamC#IJKWo-%5(E+Ar%|{Stp$`z z9KI9y1o|Tq>@iAmaiI_%ezJHu*^5McjPqL03DV9H?&3}3lLq+;S4j9L4 zV)mtK@bYF7|2bY8v%S7r(3p{mbOZPSVXdNh7Etn*d04FT5Z|g3BaQ3j$gD8s0}ZV~ zoG^ms_USQYUDoiihqAL5189xMJ&v#4!;hyze#?SEtCDAf7^I4KC^$(F{CswU2U*2J z#9#9qUFxvx`Xo9&67onSDulfk*8g^+tPLgw6ZyXI%g)TCrz14`#1^D&cO93DJUZJ( zqW}#o7QN{i`^^lxN^OAm=w|ipjPy$cEHi~m{EM)%u<*=uuud;3!l4)%S+e=wi3rl- zX9s%$>8@F1i{_P^Hk7%hSrZ>SZG+f=Oj$TAeWym$YCKO(w)Y!DZ0KK>Gw;J{I|wM0 z1I4RE4bF+F7^36Lc|P@=9pcZoGbvV!s4%g_B8e77OSlhrCY z^fpl!Pvf~t0ah1z;}#QHqo#Jb74Arv6*a-Ar7zKS4#P2^{AxH;}vL5sND$2`s&HwIQ&p_z;53 z;)~bIcntCZ`qZ>5=h##f1Pa7-=1hF05adnHeV*xgEA4w91}FJk=U)SZ^O)CKuvaf-q2pFQ7X4M7 zl%L0f^7YoG6(O(2`5=nR;q!c0&!`m| zD$szu2sANk2Sf)%%Z!Q_B9!*RVT$uZjv<+~ln^u|xBN$~2@AW@!Bj|E_xkKjoR0xO zmWnHO=r$Q^=Z0Q%&BhbHBoSj{FxoDX$s!TARPy})I$Dy1{3FRuzY%b{*H1~wo4+Pg zw3(nqk+%HK1^wkZMy=nAY-Ky0%735Dnf=3$1N@52P2oS^*{FD#FMW_tQ0b}+ZSHZz z3u)A&OWFUGX!=cfv~Kzjc|Zj1Ff~R$s=xwJB;o|A?7w=a#6^PSdOxhU95vrXsZ`-I zx8PvdcT*KsnMuX!h|(13(S0yLcyD047cpSP%HbQGwrsrcSAy^l-!wlUWRBLj_oFk2 z^R^$K$k}keFvZ`@82lhboa1HVQeyYw9+RbQRSIk9O5Ml#t>h}PLdDx!e1i~mTM}{L zIK{VeHN9X`@8&D*d!v=H;fn*N3rc|o>~_`)_uG4eF*WpiI3rQcGeKZEY|rpO{QeO} zRLk&{Y5f=rX3Go>F`{f~ZMuZ%=2TUkHhCt+el0}YcItP2`OgGBJ+|0qP{S_gcHcEv zF8&nVas3f)aFUg-wR00z%wiyZXS&dx*RT#4?@yP9WoFrOjVeJlHjn~(UTq1^gNxzQ z2FXeH*2ljxL;PLruU!ns z)mWEC_74XUbx z`q{+&%z)Uib#nf9`p=L{?xW;?RMsG>DM6Jmabt(vbO8A7p`Ub3yPy&R; zSC#)tRub(T4Fvte9kVFGv;M|9{)tioWzb@$)39P3+d~>}rnekG!682`@sq7{&e|cz zGuLChaeTYAi}0P@{)5)d)>VYw%l(-Y1uxN+QTRtbRcd1YV8nMU`is8&tmknRtp~Kk zqPG!2A`FttrA+5PEpjnQ3GoUo3wi{wstPWB89$|ePr@Qr2{&a`U3Wu~#_oEsg+ZU9 z63L*z!>>zQliyIL%fWok)zsdDs+;1I>Z5G z;$xr@w@B{UZhnGsJ&JE{0$2c77%}GCM~8OnMB5z98fMZ?Np2;95_q&v@ySCiqWo?&}QJ z_d62rJ7y@_ohWA7IJ|))5Y^qjZB4FfAJ$VRfFWOC_2Gj(Vna|_u(sujt7vE zq*|kf!yaeL5Mp5EHAv0Y!KoO&u^Gcj6GujoR}stQ~YvAV~omx4GL zVHh*j&e;xayc;We?bzlM0o3AE$`!ExHo>i!SmTb>6FU*S(xy3@c`dR!o_}`*m$I~) ze(zQ9E!c;Xc=Sv>N=1+Q8g+pufStoua#Wtpq9d06-2390ZA3wW@Z+8}9VD{??b*pE zxsaQqVvT(BAh_H{rWZt-?iNBx<%JxeH>LGZ2gTFd<@e+Za^d2jdiT$S#AMF;z9gwp zb&v3{sf@Bej5H8x-Vulv1j+Vph=Z^8a~X&9%p>T?qpm;rKV;_ANtqMoPc+rw9_LcdKuu*MmjoA7jm{B< z)Hsl}>wwT|=8>n{^i{QWI%A`df#Bm0AT?rq9zeyy(}$5d>3{E(NWKX5)sb*43~4q3 zDVZt`6|c6dFVp!m21<)gJl3Hf^^!o@BBQeIJ6QEMyl142)k*FwaXMsqN$d5wyYyob zZ!3wXte`p?Oh+e#WkW@=iu#Q!;YH&X&D1H+S%SJXj7AhG!S=?p&d$=6xTBX$3W$qb zuIeUNs#umf$$f@`YqP#e1c!Dlf*EDbA+g6fSn7<@f%GI3b>#7Q!ck0!Rk3q2fM0BH zuc^N}do8t~V|#wc%PD(n66NvOnCnW07gQ!G*?m>-!*$!dbp}l1tge6_2uvC__coOZ@1r zz%*ay71*6G4W`N^p}1V{5UT}Q0-`nFq1GCL%tM2ZsP<=R0CV%5PQ>fEX9Z+&GoetV z?6+bY(BVwWV?Q+kOe1H)o3SiXW@Oo~FsLlIzz^lHoE zk=R3lq95LGk^&o;mxB_&jEi!ZYemLLp{VGeRKeZoZ^5C#r+M+~=0;Bu81xM8%VA4| z1X?rb+~3ALw4??Wv|8uMbhDU_w9ormy@Sp7CS8G;i7@sN(K3+$gYk(Aw86T||Dp$hj?1tYWqur`z&NW;vZK9pV!=%x+{w1ntIjSikw-J3yw_Jm9!l$WG zdOb51GLcP-2bE+TJEY~3YaugY9GTfP|8%_*wiH&A09&Rd6lcRX8 zy}uKxKu8*-s%)ru_c*H*m)C(3bTUsIUl4dZPMd{dSLn{y1n*gbJop8_5AB_B`;9$r zF{sy#)gHeJc&b%55GW%hovS>Bt)SBb0;tvH0GC4{IDKdOyJ19L-079|VjtfTIb~2% zmy9vPo`wwAx_qA$gMK zpxC`Cqb|}Tn=paH-|IE-`EZE$8np89rBvNqUQ3!^1_l<^R9~AzG=jq$mt9sQd?ssA zcllr{R`AXXirVMonEZS?0AXi8(;Y6Z4og)jn6}^YLlP_u6ib3~AXgt8Mav6g!+oy- zn=RGB4OK4pj0Z*&uwBub6y%b(?NBHrtzR9!G>cu8-^~Hc`01rXUlq5$aGfz1tn(&4 zL>9odQfZEF0NnS>eAPX4iK-b~Cv^$aWgm=`N2BX=pJByvFxf)^+xT$9xB-tP8C>l( zz!_B+^cCalDOCOz+Tx&(UdT$S!!c#ku<^={qNaG77VkVHiLi1G{d-kD5fmRYaVBmj zi8bpUZN>^%1EU)keW^Dr%5ZxMV#^P4qN=y1BG>#9_wdQnXk?@`M0+`=U%tMl@g>}& zjK$s|%4V(hS{oZP*BK0((QA;GnJh^vPrT-B&m(=+^5;Tz>+T&FU)D6aaMo8Ug!o_M ztmP9U<<71Wn%|L0BU}|xRwY~WYgxj0#l0)I!G{ns-$GMREPU`iv{Opn2o`E)`OZq6mvB>7&kf!!cm-lhRSMM!KFh}%hdKRCxl_61FbVnr3d83}hJHS# z;608)hBsR&(x!-4uvJsx-UTTWL8CNDX@({W6-YEetUF;a<>;lm@6pq8VJr z1MV{4FE*BveGR4lI3QA~4GYNti&w9YwaM0WoiVUb^R*i3=<{!%Y^gp7WUE?>RQb)_ z<{{gkvT9c=US4pmq&G=Up3PCXRi&*Gk1}1K1=*_F%S_j0v|mtbl&-%{yYh*ParcF8 zK@cc5r%w#JY3Q;4I3S9DTW{VO8X$TU)W&4C#7~$cT55Uv`4q^hHb<5zGg5y)6)iOm zjDYaNqD zyr8p7Td(ua%pc+D-Ae}D(Ha?F;D@{9*fmA7BMMqjJ|a7usM)?kvY^0P6meWKJDU(H z-|Ux6vlp9IU=KKcHY@))e0%(L9D@=K$gC*;d2I&^iPJw``zoWjhY z?3NTWWcfPDi+W$7GOdaVsim~8I~N`Pu_};S3U=%PL<^Wj^ex|z7R!v#`HFySz9{0J zX{T_PIRU=Il0t%O^pYva8gdgs)AAl+F=>vF{g_y=4W#>7*=wA9>Nua}l^}zDC0rqj z_EpKsX!OCcgo(YlskhoY$C8;o^<>l6(P448>#y5^l6fqKYgkae_6hFB(4(#Ri_R9c4?^z706g8 zPo?UDh5JtLRZo-U;a*7608#$%q2{80O)W=T802oe-KUAQGi0vQ@FUw%1U^>rbEBnN z2m<^ejX~+4;&f(@k@G_5W5bkL&KiOYaDDBy#la)jWhvD=Gm_h$`JZ(WKILmj%7VFRUi%&8P#IH=A0S5YQZ)l&qBt zwUB3Y-2I70LnEI-KDSY8Rb0CCr4Ur^3YJcHIY5RM8zkmlu=nVEw8MJr{Q9|pm76Zp zTSRp+5gB~)bw6%)PkyA+LA|hn$(`#Rid0 ze{*>=DYs|1UI!V29*KhP@@2cO`W_wlJ^njh-3n?`LH$}dVN#+782C)1EaE7I`(k*u zs-yAj6R^1LMcr~a2l->+Nt`5bb#8T(ggVWb4HvKwZqtS<$hdMb;XZTE_0xd*2zQ98 zsB1t7b)FqE_WNc~T2KyEmHRcOR&??_ro;l)bR)ygr6W4XW;&IAYOxATj`Br0N4_xQ~egWVK7ihHi909@uB_D?4yg!&uE8Y=}It@|n09qI?Ur*Md-agV=FW z%t(tPp13H?dD=cE^vvC8LXFa8G3>poDrdcCrqskf)t4NXp$4Y3AXkXXjBa7n_VXA4 z;~5{=yZ1-aX_397P>n-D1r>aBhQIIPqo$e&7SW6rKc%OSd*z(MYEW#XI>Q~_* z=RB|{9rUZAR7tXu6C|Bbd*7Le9wI;|bwX(vDj#{apG26==+D0G13J394czs|0*5o0^O^GEE z2Q+Nc2wtdeDXw>qZs#cq)j{(`#n)SNCFqel14Ed2ihBk~#APM?9j+`$#?~x;xwHc< zjl-7Du6xaI8e&N+MBHZKnDveqVlmK&eMj72Wv@lxkKuNPOF&Uz7L#M@%MlcbNS|}w z3bE+Ar0Rq%qktowpPw*>FqbJQ>0lT)P_~MzSXu;*U35Ic(zz|a3e1tq$3q=svc4hS z4ysb0Did5$BjyWCC@v*UP>nZeH=AlzNMCw#+wE2B6C`iVsvvvKY~;;1C4{X7W;>F^ zPxo$<&GHM4zHL~=hVlo>9`;Jp&qXDY0)*)=(Bv)*Ue+bNw)LPV--1)zma}qe@_jAO zH%x(>zGH~1MnD3@2sy364#72h1LfH$#+!Q|K_7=0Hg?3&_dZXfwsswDaqIgl3<>Ro ztusijrC8Gh$T93eeCAxz9|QRclW~{7WEMv*x@Bs(6v%|?+MVuv9jSn6+L?#+rF6oW zrtr`~gLDC>$aIeL1*+n~A~}k`r=*uNC%6fp2~Q|)urLG@DrU8m5yG533#nf&#|y`B zzwVilH7OV2G|Ys+-Ny&2UfMSrL}F)COq8@wrSG!BcSo4e^YK{}fx5u;NKcIf&rf`8 zWiBF4+!$Zy$qPv?wSFTQ*xvy63A!pfehSCG-jtiOm+eko@x6sKgO_w9C1vk)9#}u> zU_MH-7`iPAvwRT#zz95X8aD=MwTx$GtoIb~>fxgkqlMX4^tR2p%YB?UN2eX*nn81E z*8x=6HbYR6XlO-n+k;^kp3oaSLOHhOHI{qZNabz5TWHo}@A?eRN6g)kEMjTX^AZumy6!%1W zTF6G_*IVrGOtMm3vg&SxRjJ(FteY6X;Dk(wtM1fLoJ2;e;!7EtEC#JEV9vT*xYWhC z(e~fR1_eaHc2mFu5$L%ctKdJHVa(zRikX{iB@IY+nV1ACHtFu4d5SttB%5Sf@W5V5-xQGp1q!RkEqHLLQTSCR zN_u{NbD2(q;n9BOL1O+e$eu#Ug6)G zkOGfrP=*?Nk#=P%E(5VQFTPSHTn*wvk9|-QId|c3ENPKYb)*J_b~zXu#pr|?UN%6? z%|njO07ofHstiokOeO*;ZpciJ zFJ)eFuc|Yv25)XlWIb?3&v&^*TTU2xD92MWadZH`Kdm zT}FGL-vBcsju`JnD?&OWKkm||^$C#*2v=MGV*8qBA5=Ew)A8qlh?K9_oRMF&-q>7U zMNPuzW=QI)?AqS)6d2M=&}2-i@9g3GlUE4{x789EEX6k=66*-dftOqtvW)OIqS^FXalxqP>#bJMdO z|CU#n|Am;Wsd{troq-`l=7(3wdCB~5k)ZevlR;qkr*C;5DmVlp)Jx|~8{vtAfCQ`1 zZ+cBERjL!6%bRWeC7KhTzywJPwDnqOG*ui~1!H!UI(6SWSAzv|SD(WN8O?O_3m#a=! za=lVl&UP^|G6cv+K6$6S9xLk2aDydR1jgXh|0GHxEV#QMb6I#xeII?r+T<#zdNfzN z)NjKEpl6fXAF%yIKc`tXsJhQN7}8}#AiX4nF{+M*N;dIlQ4aqsYJDlObNOo zbcq_22FmuzPm=Cg4yG|WzP_zx&A>j#^ClVy$#@S7Y!mG-$J`UxtF&; zpn77CoY?xb2D)BWLwg`Xoi(UFs$Fhq8Y&SHP4yi%@$`zYs@0oWr*=Gq5`3ZBP--&c zuqvzvp#;+PzpH>DC05)@nsl%IFy^5pFPWlApEA2i9h)9(G#3O|F%(#@{BrW! z@kv|I);?9%odGkvScO{t8V&`sZN80X(%BvB%RNa}R`-SjF$fV0w!#;avI)3RjpjAP zbhtMss5rzR9QU!h7>Rq!d{2uX@y{MrZ?qd4ryqz)SFPF-T899Wabdkz!fm`}GHJ4> zsp9VzUZTlf@o{ODmvERUC7Rh&sbRgfJ}lKBW=*#-jZniF^S)(C%X|O$1t}d5NTD7&P@_Yv?ctOUa&tSCla*M#KXToE9j8A~NgubJ$q=H0 zpk^MA;lV*UN$zwcdbmRYmk}N1xKlY+&eB(gEBz9zq*ta#;ZYU`mM`JG4G}2mauZwy zc{igX^Wn1zfP@9e+y=U38<>6JVkd>o4w}>+d#?AeCahVhl++<4k1caWHab)SzFdb+ z_pI>i`Mb|1O3;_FH_8zfX!&gBU%jGrBV923 z$o(4<^~KK16eCmOG6Z=hczK&o!u@*nx!z3gzfW$-~5Qq+GhlIjIdH3v7> z%USKAEam#dfbfFa!?weRLV)3N>ZJkZxfRMfbO&S5_oX{)WijQ_29kByD2)b zO8TXJej~zWE4oHhqM-Y}ZKL-%wuv3#B|ELSFuBg~Mp^$_H~F(*+a8OFnDMs}QG&)lu0v^qTrGn{I+Q zK(KDN4qinPZek zvg^LA#17BPDM6coz76u7rmiXnbRSBOwBa5sDO2XD$Q*Aa!AHC>6>cs1+giwl)V4ER zkFo|>QBxsDUu%30L|GFBG0JFFwV_~uz!JV#``A0`BaXZ-+(`7)Qp4;MMzy4!^otB$ z2vf8ukVU#j7it^HFefk-MPNyu&25%);yWk4w z0r=vft%Z|P1$o5R2CoGTl**#eKZ7XvEjm{AJbQk1K&C=$d^4cFmAvFHrg4ujuM~E) z8gJQt$^_BbH$9-c9AkvQkc`=V4*rk^3qntKQ zv7J~3XGp37g9B2Jf?8T=szIxtXO$7%fGHsFuvb53xoK@(Wy6epIbBiHK=TiQ=z*X= zQ-xgus2gGALHkV3P8iZc>bt3Yc_FuV7Hd|ISF!C#F~w}#9`u-!a< zaOl)SfjfJs)0;*qc8CTIW9RLeAfMOn0{Vb~7cFIzCY0ZCW%wo09Y&oXD+*pzWeR6^ ziy{XHY%6*I9T1`yyO?=c%sQJe7&FX+<$={{vq@pua8+_DP@R9LV%@5_C~Rsb(p=92pwSt@?qYXnN7=ye-2R%Ce0|(9eXC zT_aSvV3CQ#86t>gzyK)6JTi8E%`9a!g8a`vQLYOv0a-kW+g(c;O(4HB&(v#z%Yar- zB2x|EjcG45ByXh+>VTiF0AnxAdrIofx~T4CJ?f^Jk~t&3+9F@Nl|qoM8-mHm;#ftH zsLhPms(r{^PJj7h{1$zapa*as8NS42cE(ihv|EACaIzjso#K#Xbwx6bUfZ;!8syuH zxTRRO@(v(Hj0j%qP6|t;j4F~?L9JHJ!k<>IYuEvRlMwOMB80M$2l3PDUC-@Q?7K*; zV3X09L;UW)1{lpa%caJZBUX7Cp72o4bPsMn&tpo+XIsKo8fopi>ch% zMGG*H>yUfI_7xi6xL~t>#`!%^8C`PDa!-fT>YJdQdDIh`hnHyX?R=wuMv?RtWxZ@O zHUm;nv^qZYqyS!5)y|qmX_STqk_Az9J&e?L& zdXhmIBZouYVCerK#0eKtWBN=f1HESmBx#a8pDVdcYHv|>beu{}(0E@{(KR*bO!;To z8TW^D1oJ7?6OErr%b|zR&;m{=Qh+_;Ud$wC7dRc@)o)1r+#EC3RLy&MrNH4YpWdaH zK_^*21_jOST7^C5o)iBcI3Z9cWUn}|`Aey_T!t*(@^6m?L%7dLdisLimNXmo58lli z$(;%ZY89$8uS8KkVETF zQ=o~v9;>Ef8dFV3=XrFeD0uTvs{zZnJzkg3ivSdP4^QA7~*q=Vmn9A)p63WN@ zK)L{l5XQMHp(c!T8w30?6tL>qmCbvR zVnySS10ppy63WN@K%!wvW2s&~veLeMe_?#vlENXw$N(5;Z4kfVGPl-CEmNc0u1_!H z7b=OMV5*6@bM0775`M<3iPOcED3Be|WP~THCRavbBa4RqI@h~g?{v)a;)Mb#3sfq~ zF4qYTmRPTi(a~N0HaJVzdph5Yyz3h@8`F+((WrwFjW z^y>D{G0y?4JQ#ETD)pW~7U96LGoXdXXrIST^N0g6Fa28k3Zq@OZ~cL0Wi9xu?K8{O z!ycW*fU&Stj8x>WrdXwl#GcX`^1Rv0;Eaf5f$kyes*$YGW4%kHoXw2AtwJM+5fvT{fP0c}#xO z?ON9Vnp}V!XQnfB#qIB3?c>NqM!R! zclF_>j7T!a@W|_sMd2rzVZp~0I9X(iH5X~9-36y5(7=d8$(_o2gdJxWruA8Zq*X4d zDSuO%A|AJ(Gsh+U8VmQKDA(Y2(TL`*5X^m?7wF*CXuT)uP0_>nad0qy*5Kf%IYS6U zr%#_Qa@4M>P^PDreF+a%q4=jNJl;tXK!_>@+OT(f~C+<_-@=z2G5;%=*IG z0Id>2#sB)YPw8742X+wTT;}W@gG}wi$bvzl9A$apCF9}J8>&NduCbBh1g*d%QXzhJ zq?YNVMlYpC5!!Z%%WZd)4NW3{%#sVW`AVH&pT)~SS08eX5&-u9HpdOz*dm8ofMM5Xa*xr|6KGyap4uT&v z)p?@3{of~I;;-SAfoaFYC`0ZYUEwdk{V6WJ5jEC6R_cpm|EvY6_oo4{M%T*Un6!}m zi^}b8s%&@$DP3p=q$}Guzmg)r(YPUlr#VC)fg$Tv*O_Mkq8D2{a`HR!Z7vdp1zKASe zx}I(O)`#MeA$kD_hTa-`M&az(QDKm~6A;rw@A)z>I+0c7)2)bJCcYci!zvU@Psjp> z#F#Y#3t|m-_O3ZCU3m6W7JcB1HsS-Qv$=&j4-}|vP^f0< zuIX)a8*yyu7;#BXkCJGq$;)fVo}O2U#lZgTLL}ChRpDP=)c^xe(*a}{3%~YM%P=Rr z#+H+w29%~;_HQ4PF1=|TQu~ycfR{Rej9s1X@5i^X3Eky5q&mvnS?6ceomovkElX!} zA{{V%iaoA~{x8bw?Wl(?P{|7Qj#S$Icx+;q&0{x2LgDH3GjPTPeuJr>pXzTHfwL^P z${6(r+}^~NDJ?JmBV_!v6(9n=q1 zh;6sk{vcSHx$&M5l3CK$d9$&;Y{dSAgUBpz{1jeCaQYd2n`@Owug3X!H_Bfpagwxc|pV+8Yek zO{&y(JM0zQR=?8N&Kisl#Sl1Pp|Fcb-)?^)2S-_Oe6}@_+IiHrD|MmM(ySE|4m=sD zUk$X1s6ybVdQGQ5K!IRL-MPZ#8Plzb6sLi-Rm>iGyudrSg-|HdkNMJZpiC&naLyv; zBmD${30#dGG;ht8a6#v6mx$anvr+f*Z0i%Ur^kt+##|fhX-$K17mq0{eah(bI9WX% zUtj>t;I#?NW~=WJHbIORY^WX2)Zd)`kCFN&Ensuy(xP zr^Kj1*yjG6QhWGX`gjipK!!Jb za=2^(t71-W4CFcN*{s`<;Z?(Soq3+*{i#inx*v78g|J!~rcD#Bo=Ng~X+|5}s=JCJ zy@hx<$Z?|ffS2&O0iJT`u=cilPYbSXZ=4J(zOAdTcz&POHBGHcdzGfeM{b6RPcZe) zrIJKn?p+tcHYJ!JRN6mT`X?{8YahJ(X^^l=m`Alo$Gbg1u6&Gok*x9Bx9M`|LHs=N z)$*Lr)Q(D=KcnswzCvi9$UY>FOBOBQA-Z>26A=HFm&O~Jh-0I5`I%o1LPKC3q(30iUu<46scRP57MBan(&1=Pc{p%HKZ;~TI5 z0000Gg8%?0JtgFCl+u@w1Eh#Kss_$)ycfUZ=tu@&m~{wyW+U(R3vBV^L~)HzpkWf7 zWBZgr>xU35^NgY6Dm@;)V*~n=Y0A2A8Z}JFpUp{) z7m@4Y>ylT%wbvPCHEW=HMl}8p`~MRWkFIYvNh}64ozP=E^xPl5zT(KGNPvbK|%&~t_1 zC;^ra3Z$PMUKvhn3{utE&C^iu8j>1$W4!@VOPlr&jW@QEfhkz^49QNj+8hG%JtcvO zWu=`PemvRYg=~&jM-#{fIo8s^_Q%Q+&U}0KyC`b z-OZ1yzL@&W0qJ>6BxP{^l&#YJ{e!;G{JlMSFI(gh7B!g=it2{i(IloF7Td{GOX z&x+Q9#gUplf_-&fP|xx=1Ug=?Vhh| zQka-~Y?LdJ0EjuAC7^k-7ywHJu+=u@mjA_>Q#|0TpRsvAIh!;?Q`qNp``A50szeo6 z#o^bjd|0ADrJ6)(1nRIP3lo{Cq)205JvquzaVm21zifd?ur8kfhJS#MBWp78;Ygjv z{(+?KNi+OmR%;{Nd-G&BtW?B*Awh^J4kb9x@iw^Ax~4r5;r-30cJ9$)%T7CaIQr>x z3=rJNvHd}t$pHAau@!b3b#nVq{@}gwIVgb$M59r*@k>`5lSqzQjvCq>CEmK!aBwJ# zZYH5maUX9J4@_~H3Y~K$&l-wKNK~lz<@zO7Z5am9>5!2t>^I|oY9(vE)NFyfI1l8p zP8IAfR;JL%#eON3|7?cB%hY)yXxiTB{AYq|n$pFWxt?M!D98aKAlPrno>_ABkb1cC zkHyO*IFC`LEWz{Ki}4Sa3c&)b%6fl{=Apr^wUZc2P5v*^;)%9C{64fpaN=JTP zl-In^gMy@1$QF;Xu#sf4tJAW7ngemMROZ+DLh=DoC*h4)J);~CLn=G~bekh%1{ei? z0-LwwJub`JYVzM`)k{rt+s-rIA)fwmV&5P4hN@FPgo2F;aXJUR7lVqO9?E1x!p)6z zE$_E>bz&a4l#$x@uBt=ql^c+D+ynW|Fw(V|l3s3Fe5BupBOzm52WNUM~#2wIP9P9l21?3|eXr zASMLAx>)&mIZ(`d65wNgAmXS;PzRnW_Kb3&AXNg10$y#WlqO76n$%=~{I#+$00000 z0000007o;rL|T2!>QXa517pHet-(>BSK#MAdX}O=PUjSivz)i0Ery5$zVsR4+PPn zD1zO9rmVU#8R{kf^h{Nq`hID7&s;Vp3FMwXd^Fsk{Ba~AVhtz)PzPus|~+5*0mA;!I2qoyk28*V5BlZd3jE*o0| z@YD^c!d7}o2+JKY+*vW~u&$v^7*C&Pq8}0n{B4b@qT<6k%G|^)#hIfi09Ymp z20yi{6a2Vx>uH%t4_DM)Bg$``u!E&QQ@Xy}g0n?!GUuZr{aoLQh*) zA2r$$nt6ELP2k0)$5B931+da2bQG*H0<7=YIkr6;Zj2;l_pEVj`7_wiWAmnDP`h95 zoTl*m^v;`7w2(HQ$6tsX`uH~a(!zpj|B(DcEdeJ`H9BM`dw=e4@xt?Gt2y{tJ1~sO zN$uKYV;|Dt4X?EB2lvqqxwxLVlkeTdWain}huff~PD+}Rp zS)M>R(DgdF=!Bi0d)>?(@0$PGcoTbs8ZVL|NVHmsbOZg2G?g}Kbu66sv^SAv9?*<` zre3v4=`jR0P|<4Glpn7(2$zel*nME|kz2JxMM+jg73dJ~kRN^g{(LR4wHF}qOCsSN z9`Bq@Yb7pBh?(taS_q3QmC~#cGbk#^b@L13itg_z7CnU13xbbSopB9^Gfu-%YaDj6 zk2@#ho!+_(>W_ZC8uQlGc6e5N{NqE2wVt|1Q#txfCYH)PqQ{T7r`L+Q>dkx$z@(~L ziOT+^SFNnkch2vB$NOsY{Rws4#34l^KgYRz<>V=A)YL-iPT}q;Ht3$TFc8Ih7nP#) zKY4TMJtlG zKi6M>4LJHtCnat1MX9zZ*^(fqU7jxYwNx{2XV)fg2Td>+Uz+TOt=*2sKsxCTS0WU= zG;mVr`wbPCGEgPGoipHP=I9s=C;gT$^S!XpS?3sr^p_2iCSrAeEH#BE6B_UJzBuI8+%#qW zM0T3(SpF_#2f~}QxZKs1EiHf7RMcv9-JsTy{}SuP#Y<<((?WRfKsGd_(=AD9CF>NT zcuA)}X0`X@HgPP9i`eD|g59C|2wSy&u`aP~4p=--N22|9v3Yhaeb_7BZlCz|RaV@K z(SA0Td@_P-*6xf6vf)(>p1DJ0Z{`8?2pz$|^$)WszEu5hA5sbWH?d4D z)&(zYGPkQhgrj;bR8W*lh39*#G*>QJGWYGo1`_#-=IpNXu?A#dc%e+X%~rnsWO`{|6|4p&GRji7jh6BkuBSDFaQXcTZgs+cxI4=QSg zN1i-bkw7&*!9K&co#zK%Knm1o1F^O6JZv|+)P0tTDzU{okXVA+O(r+%J;$mTYC(Iz zH-UEK>eEi7Y%Oue_?Yz?pK7b$dv3?rbU@3dS8<~kDT1u1ps(W>pq1PVpIB6X+ksJr zF;b2Dl05IDGfC>vnaAFV(PMv43SBTV_%|hkc%W6tTl#108u4my{#KEa`!$WL-PtsY z_1+8Gh%|%}?>+q>{%6<}ro57(qI|nU_GRG$Qr=voE_T^hl5zz2mw+@NTna=gp(mR`QCyGuSDff%_sv7t!Z#aqM_ z-WKFvh8qH-bY=m5!s>A#fHN;|hhqW(QEP@-iG_`RO>jO%V~3|SSXXFWO|3OvW1biT znPzX%OGpgT3`ae%7HkrY_|gq8F>T-BH(cT9Z2 z#UsQ_%JB%t7sTM*E~o|V?`bS2pCDgtc6yX&0x(G)r-ZwTsf=MSC@%oY&G`%WMhZMD zb5qlKx>ykh#P4yFISe%BI&u?-k3{ht=8x!W;wTFK%tB`m8Wg#^v&Lu^&<20i@^^-;vqwOiWb}gsaD!<-X>!D#GUMFW zIKGZK9vw8TyoI}qwo^=mF*U%TyLKJFTv}fAw!!Ko{-6{>eREAuHZW6^={Z>vl@3+j)xV+K~_7H$u9j;b50!MBn0RKk_f*Rip| zt~gTZ#~HB%C()0HIFZXTLdZ3+uAEsLQ0sM-%sd=ipkN#33uusXhf38jMyu-IA$%9m zZ2_rZTvQvSi`#~V3ftaY3V;sw9J0gKIeGYO0mv3|L$bh;Q|n@!KIjk+TUi_ z$#cA-Zkk7*VA!w70JxKbIgfBbrYM?)gS83GPsWIImqnNbZ?+S`)!WjZBG}lTfTJ~+ znGn*0f^PrE~W_tIUVLF;bD;ILed*RREl zKMasbO;8wbVHD9cUeH^SbKClujpzNpk$b-(F)U(5Prz7~t+_+!D^o~HDVuo~Ft1rg zkWR{AgIqftts>&6KFtPKr4_^v^kf`3M<~|gab*P0tbl5b#(*6pYRF?o%Rsi1rH|zy zF|%snli_B{;Zythm8*HO!RbulW7H4HFGMIRE;dsEibmF3eBMr;S`F zvKP%>gTHDUaC2@*KatGzK73I_Xdcf%sxJ6{{rwK&q$<75{M*UFo5IzX0w)2*rjVUc z`N6A`AlIEi{yLyouu+buyNI7*pgf<97}LGs!O~-Bu+ok_S!DWQk50Bd`zB3tTo|!bi4IZ7 zXLs?#1abd>n}GbURVrtL>=?2h9y5bm*69aT!T(LF7i~;e9-SrDrF&Mo3blq#AgCC0 zVdrx+TPvjEamRcVjZn<_VL_H*wu@-v_WpY&3gos3>Y}g8W`FVQF zH*ge=o+XFtm>AU(8f^I3S=*r=J8z8XSZ78RGggqWe)Od66Gu|=i`ogKs)WHvURE(dX2{0(ZKEa1v-A0~ zd5mi_=Ln=F(>ZE2SQr16Iz{eSp+r7eX!I5K-wlVE{c~o^X2W1``N~b$}Q26J! zWCz-|+awk;Oh~`LjlVpm5>JqWVELu_{p{iFgW5dtqIN1Gf3bvUu5~65sa~v`_nHLJ zhO)JOPogazT>f49`>jsQW*W&=%Q18#f}Wf#)yHQsa@8jVkWvz^0GadNZr_tB7lC1v zI-7u(GBXJnYtAKE2*CD3pJ74{(3H3*MBoK#5uqXT2;6G{lDFxS*hX?F! zdvWAUNHEn3a~!|3bu=>SNkJ|z_4VX&?@#(&bl|4}w}f|t%TGMUprV-d!JG_3`~Mj_ z-_{dHWI^{q`90NNEU9eMYr!TD2A-|A4nK-Q&FXSjB&NtW#*BR%?sKiBwL%GzG zdh&x+hu#!yDeG|8eYA?{;8Z=9kk(Cs*C1>Px=)_uIJ=24ef~#l8~Ft`>{jP?kmA4 zcH2wZ%{cS^p7aAOFYA|C}P+L!SGU)=haSlg482L9|ByCBJXPuug(5?BJykD5j zLnKmigX{eW%Gl&$?~pV_&1RhPJK?LdN`Ol0J)h;&z<^_U3<*{$;6Sl%tAe?-M=3nH zUPTBf(Mji&m2a)nu7gc7&8%8&67mxOuDw&zK#I;n$TncIYHINOgDD)C*=h{e`-i;v zf8xvP)o_kdT+4=orm`k6)i}7bUS2Cg`!c;|sO@@o6VO-5y1}ua@zrjV!3}&))jO9T zJdl+IF$vHU6cOM{4J?aYRBnVRUd5z3q6>`$hZx!8yI=njl{>J__(9^lQHclF8TIhX z%xotZ3m+Ic<`)FKpWSBnp03~vgwG=pbf*gw zTtey}(4EY*lz2cmZ2}1cRF<2~agmn8cQv5{KPDqAR4D-Ol>ypDKE zL`wER4+caY0ge1i%)L)^-;{C1oJUM5u8nRi^^yCAK#foZ_x{R#XWhgRvjDjbXV{kO zK#n4}T^6XmusKQD9AP5Ag)pqPF$9$Ufs347+N!?s7AT;j?Ug!I8^XWEMfw9~o&n_l zhfuXH%DhvCWE*WJgbqh&%oRhpOED@ZbpGdDb=C%w7k#5@V@XjN&HO%6Q=aO>7Ucp!9d%@Iu8};G+3AB=w~nKJby}L; zuhbWXK?eq$Y?pA>gaC)oAoPQ8F{V<8#|3X;ojUWS6KJ{prOjQF_F6_O*I^l z6Ekdzq{bX1U8|wkI?I`jEP9jxud7Thz{hc5|7t|3xdnihW~1}f&!x$kHQ%(?j>os zDE>tfC3H&BMm#EWH4mMR|EQUi#t}B8_8xcZ$#txc1q{ql&s=UXni$6eRGH=Bis$wK z+>;sjg=n@eFIQprC61SKhf^Jm3i0a|%K|a`<+`0b&&;#H32-Y^(D{mJxQQ-g!9uc1 zMVzwe=BG$mzH)grr3txPWY9u921G=zmTBPVN^T6^M)n0LY@pkL=}Aq)YZ9h;qE(W( z&DE&!u~T+zLv(ShmW`7aoO0X7VT}nhGVU&N5`mE=ig7yr%R15X=g&L;-nNzgRp9u0 zI^f&3)Ce7TaVaB&Z82F9PTkD&U)Hs`%@;o^QStyfqG|wF?L%zNoAj`fCx20aBKjo( z_{Q~h{ENCkLtEA1<7Q6sZm<1M!~3m(M$M5?)%bDp+IoywT{@vYoCBi?Ve=N6e7bZt zUykApG)6|LDS023LhFXqeOy}#d)W`#r9|NsC}&O&BDIrC$K@@RJB6WeLEusW6*>r& zLq&7 zGWU`YvW?25{p(m4)h7w)A4-bjr7EkrfBnzC_tz$&o7GD*0I9%bxIu-};mK;^G&nnOGOT4A#JF|Xsb2aLYn14eX<3obRa!hmS0sU*-Z6xb(DsR zC~O@$i`9r|&O{FkIcIz2vlE{vXJvsfumVhMO2t+SqK3jZDuL>TM(GnNjCKJ*E=~{w zu)|fm=!j_)zw&KK<=3KXvA^muZmOr0Zp9WKS{WZir#*R%)VNK0m-F%L2@klrcf*|s zSqn3kXm1g&U)Uo7C5h|F7g#?P*hhsLR@-EP$O`ch z*JhH2ENc8#+p+W0a@3%@JjodcSa|~+uum!~hEp*`-wL`Xtpru3^Yxe&()p&M2l&>T z2?(m??Dem#XJP6oL9bQ(@VI=BtaLKsih)8=vo1lL-;&UG)~p(t7?R%2_TW91=y#+f zF6LILHf2o-JM}AQ?P{fe0A!EmbO3-@_@*uS%3-L#5v;YEM8S9AFKOq4y#FyGb5Kld z;W#`CryaV6qX!kN-V~~gI2fhF;0n>sT_rv$#kCMRSSoJ+4u-t{Pb}q=pM%YB)9qaX zEL85vJ~_+V#Gt}>jVM*^>4D|;k(4G4O!$iJegGnJYEbN^jXuAp#^ESs70H~Do@BBb z)a8i0R(6BAy*&j^hL83M0w7R7aGn8?_!sGx_z365J``tu!k%rb#r;@jBMOVIAks-3 zgG?`**aYf27a5gd5jbSuFe^&2*PLHwIS9#3nyQcIy@f}5PNteB`_xK`3C0k?&+kXp zNIb+MDpro=;t^!Zt`Q?Sf?O_-zdJFc{hh-S@D9*vC^++XRr3=VU~MiL#fQ*kxiDj) z{m{?LygqgDni3Rr{|Qe5;S5pcwm|77lTEL2M(-5o;9h%*=7h%w;F;C%=icQX&}0AR zB%MRXthr&|VU*?A^fhPf`h|p2rXbHJLji?sB$J=`Q%tR>OB01WuGHMUt?oej|G@0| zm7^(Fjz>lW%?T9RLGRkeFT~bqi@{O$@fe0sQ%LL=BA6l!Mv``BN{tx@_ss@fF~HGw zU{$sb;YT2(9sm!1=6RT^0Lgt+^CKLwyFFCRi%T>~NXk+Vf5xlNyE{@ik?|1_%Ltd( z+V>Fec;=&abWWzRLyNI5!GA6xlNq|L9b=>{64KU_ylv4Yo^iGD!Yde6-n>|D@QKlG zSFm5>xF{qNoRG+^cX@_JWD?_YFFz)_i z@~+_;_&zzX@1F`Rhqq&xQel<00E>?fD4p47c*VMufh7S4`Z!s6)QciGu2T-wfu_u1_Hzt+8O5&0oj zYPZFCS%pIkZRmN(Zv6FgLs`0s^s>6$%AG25j3`w1qGix?0{2Q+*IhMZtmV^IUakND zJMvWoMC&2G-#hNw=QQG1rv5P$rp%9lm2eO z`T4dVKrsR>Pd#m(q@zt>v7^Y_RglbYs|y8jR@mGdR)M)A;X^M5IK@J2^k#~ovyp_T zNnyUm;lq)rF+(bKZTnrpY;IQ5*K{Ehq&Hj zF=;+Db;JuZ6*z_XpnDldZ%?Bp|DZHCzz3P5B%zbL?d>?NJ&JjObM*upQha_PAX^WP z_4fu0N9T0)k?As_A%Gpr*7y?NjjQ}ZD!>xj zlRg532xun0>Cw*Wg{-cG+d>QWz74*9Ni}G@{r3|>OR{}S2NZ5d!1J&XV+t|CZ(8Mn z*?WR(rmA7hOE{TWD*Mv;EclM?bCh`+I(6bKk>AWKb~>Me+s`iyb7vW+ZHf7%uOCJ( zUE<1Can1PjVN^R~pOPR8uVUsC5Xa@w9vZL_$xKmBvY#)mn9ZHnVF)fucHd97DyYI}qb1-3 z5leVhQ`J1M;#rTCHBwC4TCWOEPh;|A!tne{iXa~-BiZxRgF|4G&@D|;JYV>rxEWv{ zGhj|~5O)ridYfgHh0liLBQpOhW@Syx3*QKOxz%8#KUjKpI=Fa?YH5K-`{Bdn&o06h zre;zmT-e+kN~C6<#~auueyy7Oxa%CN%3^=rhEU3e*}YZ$U1y5w9jJyO z+z%;Xs?zvBq+zWej~{Z6>V|{}vK%6yW8e??XMJ|H1Z9Ten`FNWT%*6tS zVlM48H^u+}eY!=qNjy^84Y%(#K)U_1a#e%)n$BPJV&DCc==0~vb4@1U6uN%p1Pb+r z3CPLHNukuSY8fi7Hn)Ga#J(wFCn-SYzN?!s#@30^a4q8pQFUwM7rk6h-i5%mw=JN4pN~abXj}9RK-;=efTuNcdPX;ML4Ush4zPrBUGLFkWhSdy`0(nbzOz<+% zA4P+5Qj=CB@?Or`$C*afh~T9M%{?3E+Nz0u1$1RM)+&*{gO;-W?9uWgf1Cjg4&$y< z1IkhG*^=ZT@;wr+%?1%`{cm{C*dh4+jdf9;@GzQAax_u2s^;MFgf6le40AbkM(@!Z zRI1ln>>N~nYVN)lp?;)@8QI!iy}~AeWsu+E;&UPF?e&iH>A@*dO2N zds%1ADdu1-D)$KRq8rf&K<~w|)*22@OozbVlB*6i9&iBOQ7tQqP~b9(%M>veDImy+ zIx#Bg-45rtUbP(_$z5|iL%BS4dI*;pLbQ4BIx;8vwZHW35b0$LXDvj!%Z+G0z}6fr z4;SCo$g9~*RyEEc(VvwGN*HI%(~SgDWx)oet1JV({@@_jxNdia@q9Wk&^Ej34gODn zWj2D9A{X_4^>FmYXLh@#(4J`y~%|bR%w`C!GO`ul*4H==ryF*V1_k%6(m0 zv4qZ%uKPBjv4l6$YYYb*)Cj1!J@0jZGPJwT=PjWR7)yNZcJ%!{7xX$uJ6Jw;^8mz{ zW&B!?ZR^8sA~uCjg`pFPYLXHKV@q;?1mxh*?R;&sLj9I;3@AB`un?x>Qul*KLsFk2dh)!f=~>pZWT|Obk#-n8`&=d&JYz@BpIBt%C5z}C526bWr%=5ida>1yVlsEj@ z$)ZzPTdQ-ouM2y`UjR%BZB}i0-ag_^m(Jk|o0kK+`&sm9nwXUVhdk^zsd8Vw zf>1l@z8Yc16*&?w4DnSV}HYr9|*gFQMhg zXOd7l&rwet3bm?X)UmS~X-_|Xn=T0P1;}Z0Nvtvs&>Ep-$aDpKjUJHRk#UXh^K=cp zBCnhnHf@6?STFJwfb?B{L_!O=*`DXd>pigGcm_Tn8UeZA3#6l@ZWkUngA9H9j*imt zKv^AaG)5~D4J<{?8Tn1|ij~vaGLV)9)$1ABfMQ zKbm9w<7R(|JhQRN15Io>4O}AKfh%2FR<#ta3VBRRItt<@U4@kGIvsF}qXiFoZUOvn z8v%PG%vm)y>vR~-vL=7dTp1My z6?$=U-TbFyve=$|Iyp++}3=(|gEL4{lZ7Osp8fCH37WQhrX`J=0BGLZ!f9 z*<7ac`>kMKf{S=eS9Za=qKN6Z{27cy;5(cge+W(8+Vef?%AhHjnLmtZm~#l8I59`a zPEs{a1669u5EAp5j|4q0+1a={z(ZE5pGx?pMiWunNz(A#*35@N$Ttq+Ywc=C-m69# z1)sN0cii8@z!~^|Q|#&dqZ=q7d5AXJ;=MU$WB>pF00000000000000000000000do z-YJg;pnQFX{)fL1Xt(t^j=LG~*w3)Lj|N+MaG2L?m&%8zy?-iNYw;64{MP3sYjY2$ zJ0_s%HdR?`~+Sud+fi?6B^=PsjvrNLae3FMJJ*gdNrJk&CXHP>ms&(a0 zdpg=UAo^ZJHz4(DDtf=g404zs|9c|E%FEwbXRP@o@$S8G?G}X+- zL<%@{LEs_ep3BS32$aqcKal@foLSq|^O>S4IAy+6uA?coUt_^{N)03rWI z0gwOy6EMvwJrHXZeiA({Q|k=y14kJ6sDvrO<57b2X(Ds(o0-9y05SbkRml3fwG<72 z$n46{KtWi_P`aE%?@N*|-F90HCsIvLf^UGlp?=+Ir(!{UIU5Y~DZCx<1HfGa zv#2@ECx2=VNu6Y4cd3% zfw(fZ@`@nzFfM+_o34IH{>UV>koNZ4N9KjiF-vEgfPIcXZWt#Wws!MWZ6l=y$A!eo zzF)Hm(x<*Lo;&{S$EPjSKDZqudgM-BoR?)1m z1jeHH2#avw3cM@*Qe1Mbb})X$lYg3~SFP$J^Nyh^( zj($8qQS`505Dvf@AbEyu$?=wk+=3bvrG7 z9QfyedY@I@V!LI!v7mKLfEd7mvpLxATO}AS!y!B^Yoo#V!)!n8L{tNE&$L`xU?)$zE=si$3WW?Bjczim%G92OR z`$_R4KT~Veadj}RU?LaIJ@8TF`;&&8&;SMlx%Z+H&O_3OQh8sMp11D;CX&WQV(tF;>B6>_iGOPyFNq!Igzz zGfO$eW`Gt3W(9A7(-tVXcS zoO9xybrS};JIwQ}QnqhRn8u%aF|vVZ!5va;^t{zF&{2_Fkn)cT^#S*G%RMoqkHb}V zE>B3ONNK!0o}TwzJw5<`TcZU$=(Z6liB>n+2k{`g3R9NI zR>}=|lKs=>D{23$t7@>K=vY_=)LlJp6}!ZpeIW1Ci^1RacU8HK^p#;bNY$a%hFlQyLy0UJbsvylPWHPfwj$Z<_)Eg^2l- zn3~kU?lFSGg=#Zqwx*`W)+1d~oc%K%@;sHcIsS|2s>lH5A5$*yQ19kthav%-cCpe5 zHJY|l9SR~Z{oZ|MNe4n*3!uG&OhRW30KNa-buCh^)^CAE65>}ixrm=^veBKW1ExM_~+%*?J!n5xW-Q9FH=(heZH*C!2_If@Jr zk@<1<#Q`ws!0 zYvK9WMqNne8nQE_u{GhJz}P{OjVzs+p6#urGyKe(YeZFLU_F>K&)Zit1VUb#^4H13Ci)>0z!|*Teg{&ZZMtEvMRf2r)e7i z6`RTYLjZC>jlVIErz#uXn?(~qrL{wRHd>THDwU`p4=80Wt=Bd~DWC(No4aaWSt4f& zoRJm6y26W)&y!nq4{=WY>stG;1(Xl~bhL)4x3frAq3z;7GX5cjB?n0&s?UiE{~6bN zI3aF~&vz;41!)l+hmf%Pdqmy^qJ7Qh%?njFJy@D3FiCcOOc_S#>du0LP^qmY)G6xF zlXUULA)0BiI~hG`>(@E0gJpK7|Gk$3l$)aQMv}fJR6`i}%4R2UD0F0lIZB2`EfEZG zy~>dlCsxk{#Py9>LU&70tcx?4>2j)`s2#|omMx0j*qs4 z&E^_GGiMC)0xsv9S8CFC!!5oI)D&L}#i*806OaBmci)}uDHOnKZ6*f9WR1uoZbv+S zq=DvulxDHVO`cLOzv5OJp9~0!=2+fxx;d8iP(;BQlZ(Fj9R$$r78LczAgSLrhI1Rt zBUE6$$XgEh?Cyc+M-@^C`N>qvz>jq|Ud&0GE+j$}nA+o}FBk6SxTEjAh)r5Z-y&pS zpaRcVqXoQkR=!TzttKL(zE{yZ8y?@%k%z_Xl2rJd$>`=;Df#coKsm#bLHyxXPc61dl&D8F1(cV9ixtJ-}4*_OGIcG$%Ql@ z|4&)CGPOMu-eKC{-FRjuEP`*O^%l&rsAJeETe=pK;kBV6{E9%&FA+9W1+ul<) zEx2HWpR!|u=A@{meJ;KNU2nD%K)9%=X?CkM=3EIWR3V{XuKQPWUl}!jX&asOj5|*3 ztAYBj{`^XTehI4M4640>j!l~Th0ib_?0Ul+SSXogh9L#uN2o_&@M z+)bc%Fv3*)F&HYKs4nKm|*DC{QGCQq^tJ083n1e2#e%}RJUTBnaniR*Kr!K9lf za6Pj+mzD=y()A$pBMP-=KYscrW#wM+p;`522Ce*a41Zfx-b-rsc=;Vz{d}iKkc+vn z^@BD?HZskAC-i4L9USlKoV^eRf`(YR3Od=k^3KNZXFvmzpwO=WTmq2k(Y)5~y5B`S z5+`3;wY9G_rO3lF0p|zsgWEDO9D1J5AICQttXDx#I>ka-?n=f6bZ{!OBiTsXNx>hA zdkzm#l2N;m7Ouxz_vuh12?%fDT`ZZ_0CmmIIJX7w<_9s+?mUYE?J3HIyvgN}$BaLu zGfABZjm4O?%(Bx|nmKakuFtK(imeiQ?8dl&S`D`R(qRt}nVQ96k2)+Li zJ2LN>w&E}hrpFM$cHr+|0R~x-_%s3#7&N+$VeqY;SrxutuNx1%r8c3|V<+kq89MQh zeARO%x;=+2Ih!TxpK=1!o6Wc9P(kN0zlk4Hq^hH**sic(2Pi=dcQU%swu?>TY;7F(XA$O#Z<@-{873`5@~hh(+KY%YV3${U)K?kGb<>Q`tN zkiQR+8C73=dy=T8Z2w3>(a7INny$zci@g;0ZAlML*)ckDXbUMx3pYd~?EwaHkoqG(Fa4(A zF;R<0Jg|jpyj!9nOm~b$Xi-#56)Eyi7PuGIJCnjP8Ufr@tTO0%xE4m$Gt?C{8ZNF` zM(ftqFUI7k)oI5JgCyP@n2QQxLPXLWdBw&c(`EN0ick z@+u%wBpM032UeSmr04HRearm~zygsYX}4X(&}aT+J5OMUl6GF10LlTd%3Ahg#x`D> zkR1FYz>?r7_LY~%vnl|GxiXrIS9lc!h9Cnq2ERlbCZSUj?s5>o_8^QPBrH-Os>iC+ zEj#}iAaW^?R! z^$(qKqpK(th(?4xhSPNd2flm?LX?25&))BL$u+GTFHI>%kwOkRc>yu|@&YuE|AqfJTSB-VE3O$X>b{FzRmS26e5 z-$JM^aunWIk8+x`M6HrybL+r=ZOGP~cOQg?W_S6%_^-Ds9YjD=PMZ!*$St<3PQXz} ztbw$mgK1N@c?{gcO-}dii=TY}@UjR7E-|E)@mBn6M}m@5D9(T##&6H?C#=a+HF+lm ziI!1b6e(-jeS(oNi7KX^I%tT_EONEg=7l_u$J)Cc&r6M6r&1c$qC?~RM|q8GQ2(Cc zx04umG&$sXue`TrA}R)VTQ5y1M74H=oEE9os049Q(1_t?O&r8?QU-;Ig2l5Spaxs( zWKbsbO@au*0li4LYnWispGn^6?ZEDI`DWh!-#DFng9#<+i|oIW2v1xp_ijb3y)s%( zCUR08Y+VCn@f1A{MyJ_xx%8~q#`A7rJk9ca5;wVwa6>yed?Brss+e(9^Zzak`RBO# z|L=j=SOmwOmy#n7hC%N~s2mBevIBrVWtOSO{;YCDqY1hMAB zy9yJevWI$>Q`2!20|)7?Vpk^SGI~{^kT#q<#wKV`fATK~QcZHX9E- zS4n@X1@Z+Va7l9R$v{m+lrVNx@rn2{(U49UFVus%K0EYAyTz%`^6I;=(BYijRaYH* zww|3-)6SAkN|RCeGY7EbO($X};uBbC)MHgAIK=bPr@jb1ZL)R4QDN9k4lCo@Lqwza;MD7f06ppJ73!rX2W;^VrTIE9-k(vOVQn{FLbT{-^i1@}Q5 zVhGN#jy6R(_Yv5UUHQ<5qiMw7okeIO@Ak^?GoFABK6HMNA6X?zLh^?Ujfs!!T1g-F zKEq{hxCgG0ag?uTA=Y3=dA5*1eZCDVq$x0Wwi*UZ43I*FJFF+;1y_>j7fMz#`4FqA z^f7730O#|tSf?X63-aSJ*!7z|MQiAE z`75y!ELKP)PSn@JQM`$D&PB(soYEY5ea9FMcsS54`yW?&=C_ap!4Asr29ps+9YM96 z`tlI9la4)^Y=U_K+4fxCH(kiN3z5YLt7rfK#!v?il8SylWBf+sz3$|2S9A7a-)_7Z zZo6UE`UAolMjzZVQwPYh7HGXIVV42Pqv_ss6uyv8m`=xun@ma~TukDZx?ltN*LsLA z=YSv^HlqcYn5o_e{qyj`;M-;%>~ya->Hh9Ia^nyb5Q1rmA+04aDUN2|O_1U5J>gl| z=^rZEHfs?fN1#kmjQ)2s)@hhJ_$V;eVhjwE+i`rx%3g6F!$m^)gdG8;jSp}>MMAwY zg(W@BgFhn*ewYp&*BAnBj@8Tn8hvU>NmDR-j6utNh%@xmw+Bd%JB#TP{dkv{`pd7< zm_*vPxG=HB8#&;OAwn|avYb$)LBB;wom)A+&v9daOB1H9c-Bn$E0OM3A)(RX4|d~A zyp<+_2)EA-rtDT1ZvO%pD!e@cgZH>PUyjV4t=zmCxyD%#WP#5^gZy|7K+e$;z!uS0 zLk#a$Nx|N7$N`W#!?o3plU*RA2u$CH@GUFey%rpI2+2Ta17;nKBFYbKBxmuK%5&*} z9$8p_Xl^U9OD_QFQ7xt-r)2y#eA%2BG)!&=yVLqjk$uOEVH(j@dP^i)WzriYxK@uV zqZ)zP>0;%NO?4E@`4PAO31~-(dZGXZJ&q22&PpxY<+LvVoX(R1Ja1V9^yZh*X+$Ji zi}9X*&I?x$->`HWgdy)A@SA7=P5hrpw^?;RA47&qJ!!FMqM;UzqPuq~?XjVJX*r{& zO`q4-?^QX*N0P=!X4pq?ShmeO#PCJ{`JMhsfnWdypkhMs)nd8bNp(tCy)Ty9Rd;OI638^#LEy97ps$us) znAiWe+|0gdtPw;N>UX>HsT{5^Kq&5QRWZMdm&DtdH9zb&+fJ4ugpk%L>lIPL>ovFc ze9vEalY#CkiYGr-X!arwfHx>6TDfL4+KroFlH&wZCWu4W2_D(ybZ|cH25Vk_)_U)XNWi9w z2wp{So-{3bTV9XU#392fIF&6{<34iDgNjLIbkxFBffYDdO^vFEP~YQ*9b zav9NxK{9#ui}X5}l=6c;iwPGjCN|3Y<0s~-IZyzr>(`;AhfxmzNhgV5L=D#{_r}(q=tFtXV|wKXi7Fa<$|3a_oK?fbr_K z%>;crxh+2T-vNbM)Sj3`cgoFo5=O=68!IY_#DokyP6+A_txK$GN*oxSO@{Z*xPMb~ zB|-Kpm?ib!A$d4h--X`m9)Fw`T$y!BrkG&)|?nX3NF+6sfsv^^6Z8N4_|MP&(yg|}+LG@!Ar)q>K zmeoIP`1EfBbo1$ouB;-;Zvs&K8Dr>(xd*j?d(40SfN-xbSv|Fh1cs|?YAeQrcM zqsWTnY}v>}V9OZh;b6I_CKp%kx#^&>h(zb$gFnC3p4fKQOyp7PD@T|;D;L2`oJhge z>fZ|VS z9x}vPRi~Ni(ZZqq)wE+<$05c5oMd>A6CAiuCuYu=+lPN~_@f1zxs>s%gS(ixzJ_Pz zzdFJ-vtP7-9cjs9PPXJ$HBRM@U6rFcF8^u&L@NT}C4PWyH*DGxxs8 z#vU_85Bqp@f$C((PFm|Ch|u9J&XFZI82mWzFGx z$#;0L0%;mBBCh|p(p1;!(u*4lh82btFT^SIrG)(7B)p95pg99KB8xg&1yBIaOAt~k zxd^?fP1jYBNSl>5McH(T_+DL@HNWGPo%Gk(dJ6Pt`C|Nk@|$sT0p-gLS{;=j34iKq zN*bNFR-7zC66qR?MgSpkIw5g*EY)#4hXIr`6`gZ9S)-g#Z6P)aRKdICVavH*ewgCv@8wKQ&S&*Oj0w*+n>2{e%lPR7lybiwiU3+*lK z1Yy4ddd7kel%>m%O(MjSS^?D@Bnu{*NmYJw5B+N4F0L4=?4OFHon1Ued}xUY-cyst zG-_i8$sekbp?qmMqoz%t*V&){gRFC-A*)yb72b5Ea>zb4CqyFt%1X6v!L}04#FcRW2y0 znB^R%@vhc@ev~})U^Jtud7_2y5R7@qx>1VW&fmZ{|6qkQvWzs0)0c?~){g#w`E~#CZ z*ZZ1l*tRbJ!pXwv4pXx9g%KdfdVHqJ)Npe@&OU@?UI4OGO_GDo>RH7;vh$ofOs(o; zqz8fgCEB}08pVo8rOvhWroahuw+5fx>>q1&%^ z(1Sp93Pyn##A@2Z?BzIQMus+tVu;CL3e6aoCqzF{4+=J-|AjJOOXJ!YF0LElxqZzE=NPobe1Ct;IA{EFJ4w#m5-Y&lvW6w=9 zhO>G;R7>O_$h)uK0@b=2Q&&o7Nduy@qSPq%>CiU%{Ps&r$kHLe00LBY@(3!#8DoI6 zK3fS0N{gNQfAuTDg!{=5Rqz1f{LNkxk=j~j6Q-O9Ydt9`N@7e1Fj4U>k@;NU*rkgq zWwYfT{32ZOWJL}M_^UPbv{2}7W;10hcaKrTstjgGm-CPYfi?I!8g$}Zwv{{^bg*I! z=%&G28Cd!HgF1N|&5C>e-XM^SNu9vS#}G5vZ?7HT)3Q4hXOUm<<&tEhvBIW+L2^Nv zGR5K0^PX)r!2WO=81U3+$=*A>&yIq;y zcQPPOI%XnE%Ht(MR-14^`}`v07s>;+;Axj9BoNUN1AT&KdP^?|A{>Q*B7Wq=xE|&Z z1+wQMJTiokT~<4ccbl(ru^XHBnWK)UXv?AazB7Ps>Xmg6Rb&AAL&j5GzJk-Y_%(z8 zR4~w|iK$GP0(7vCAD(q(1;LE8>p(80Z)<5)&rIVmFB%QgTpfLhlyYp&`czvcd#Iey6=ac_b@D< zlfG+LHyh3O{zZh{DjgD8QHCr|FBl2J0ycB?lYMa`mv5c~QnM7u^6^ZHcN=X{_fy^VP>e0hS${ zouR(U4cECIrRdZGLZAd_HRcD}AD&OFt&p-pt3-?&0E&IlwkNlLtxK_+l`vv0K9+|8 zKoGZCY(pqE8wGJuW$fa)H4~%!*#e8)Ccnps;NA<%&uu84J(KZ1Fe{nML-_MjxB?^) zyMMb+bl6_DN~Pn15Jmb0$MXDjVBjvR+JZD>uW{Rn{*`YR3d~hfm@y7-zQ9Fwi8vD92H9}niN=UX{ zIa6^NpB>EcS8%k1-G~@8%1O%S30YRaIrBaT;{7Ze5^9tg(ATTX2SJgO|FC&>u-UOf zAoiMF!M|AGPd2PpsM_bog+G1jUhL@q86@>n)zk43x=1mmb{O~L5}Wc<0xjG53Z9+2 z49<|Im_M;$e9h=Znc2@i$0|I~hIGUfYBZ7$k?qQ!auS2wxQnR#ooufx53!0!1ZBwX z4~&xy&cXWQ5j-;dxJVgzy9wLOa%y}eyuX*^9m_e`8)u+~o!TZs>w7tDo3o;`?jrp> zE=3d0#nU`M15*xZ5RMJftfwiTU5sb8+7PE%P;A=;^pvWZs@$($`66J}bb?=EnAR-I zsg+#QiS<+~4h-YhOC~bKs+-1pAw{h)4 zFUx<4dox4;e~>tt46aS}-LG*pj)ite&VUy)r!Ag38T#R6H)HQNfUyM!(cPYiEgA!{ zcpx%}yU^^R>p)YIq3YE!p(6Pba9aCP=x5iBB8If7kgL%B<%!4oK&_N3q8D(Vy$kJHfQ0w{!;kVu<4`>VQiDQM3@U0`b+pj3C z+m@PAD+zqSD!pWLVX8E(_aT80gx6%Oq@3@Uq_zbppWf#@J=Q(t6YUr0q@o*AFg!45 zqN3Emvz*zGZ#W6H!c~+7)S*BKrEo&}tLChdGn_@^Lt(n-ckr2|)JEEw5#5*2ouJ6T zL?`%wOEJ|#6GKunoC04Lm+qF^*=k$0)#a|@qhLEVlg4~q9GIR(7fc4=szl*l1(jhL zcibMKX%Sl8@W$WzwIH*KqYj(+Fp(nBa-~|ir#p~wcL~MR25R3&|6S1nP$;pN{2k)E zKIw2D15=4JqavKgR=E?Q^GEWYIY#Su0wUq+zjEm1JON!MuJ{7r(GUfcR6~SMXk*6` zN2Q?I;oR-!Y3_I6JV9dEpIqOF=cW+gf+H$5HBl&wUJBC|7j&;FJJnj7eRpeG$0aG- zrVMAcn6gyVL3TheoJtYc2oLpAw#A0quE31KvB*Iia(|A`7WofR9%v_*t)=&t4HA6l2(2WU_XR*z_#?gPrPK((s%)&REI zzP6wSKWGB;eGB!$w~v^5&XRWFW9rX6f=F1~jUk9yjt4SK#W{NqazjGZ75W|apk&|V zTa3SDp2@Ay&QvXV6JV){D{&GQMTWkia|N|C zDS(C<#7cD4uQMl0(pt%bsP(XRJe+pYu0<*o$%xmEcn^1j66Ar6$JA>k(Ke^DicDjG zx`NO7q@zO!uUnqr;d)s$Z336pQ6B_0H$p~!&z)(^fiaP~=kiVSl!{Th2uN@$WB*tQ zK+(a^_;#_@)dT#K3o211`5|Mz{M05X(z?QMz{ty%UZSRx&j%9sJ>{E9gFK1+*{1Jj z{oXl|zza7YIsugA@dIb~asMbqc^=C#lVHU{KKKWKchn^IMEJb z@&HaAA?0CWRX=GS3LK9^*-11HvDBt;8IHV2ASBV%M+=L zZWp2m&qc!|;x8%6?D`YM$iBPCAXHTD?zFnlJME()dRwpm!xa`YzNrA9)-k83d0lws9Ep|-8 z?REXDR?F+AfwiB(S$>}a1#VY8@a#r^n5Y40t@s0@#rqL5&o>X9fPOG=+o@+_jA?l1 zKmcX>gL!Sc6s-DQuiapo44cuV!X&>^1{8s9@4RFu21KY6|3j|Hhk z4rN^2c=3r=w%+)~*R3#eib>MPZp@w0ZOALH&r9ZyRo>N`;TI*Ju?(vz{sODDDhn{s zslNr2#~FK*Zh0_bjlJ^cVWO7LWumPwTmg-i`K5EI;9Xe@!DV0!$&m%n-%j-rqP7`S zO&yM-tii0frt8}9Pu`Evlzk`Ya5Dpem>(A46&)FOBo4h@VYkp0X8mL~z+16oZaE?$ zMU~}$%O^xbZ^SqdQlJq*kJMmyLOS*}kwGlme%>TwDT#i~hm;s&K;0mc=1Oo1uqQ5^ zmGih%HnG20V53d3D8iVpsC1K81Tl$_x;`tnPdg4{hnl{lfXeI6*idO1!*GkuB=eSx zZ=Mpp+4*FE>iR+m%zXN!R)+(p<)!Sn;7Tv5yhwi3lRAm73-*(YEEcoiVQ_GvElLdAa$S@k>Gq^>W`5u!X2q$iG?a-A(<2PC0x@Ppn}Bk+&iW3=2wQ&AF@qk?=DFvT!R!;_`;(dxgk5p2((R=&H${z`QX$be$_ zW+PZpyxV(^h^&FStqyLc>^yzLxyrr9N;UYyw<5l+MYcDqhZgke2zfI>d6G}_rbA*+ z?pF4qd*c^TSYbAS6%qa%EDPcJ4AV4nKEMFMldFewW-9)f>kQYXUmlevC9}^!3XFU= zSw!q^jFzE)pa&V)ea+&1;x zV_DnY=O#IV9A>tpO&9w?FyeJ6+G@s7m_V8C(Jfdbro*2W@i5%`WNyD(`vcVnZUQ&w z(&jy8U#oRJPbLE+%v52U?H92I8Fwg{fk`kYo-?~aF|m%b>lLq&5@QJ=zPHeCVaCZK zRYYrl1GdZVP=byhcs1zsy$+I-AEGgM=*}5{Vl3B66!qSbX))i47MiG(k@Tde=C-Ge zf{+nG>Yl%SIe&OzhsIJ*mJEO{iCkiYN=_9zgcnS=lWRL5TU0GJR*00ZZb!G~=<{u+ zsiWk(Fgqwz|GoFuGm|nalnS+pMx{bdoBh)?zKf1CQozX|Ka+SwG_fBhZHR3ZO+i94 zYk5@No&t@$jrBGdM8Ei_8}c?J)+sd-T4@L{bKkg#WPfW~ByrRr|lp!r@Tvt=LrX+NU5jt0%Ca4 z2W9ndC?64h>-;@wu(t?Yg1(99>+AE_7f^kWWdBJ33C*Tp_Q~iK? zc!>tM&?QS-B_l@?w_|G3Ha;s*hEhwVRH?C+{c{OsWk^(T_Z6z_CG${rtpzBH$haf* zWi@S&L38Wh#l;`Eg>Hs*p~TWnTLcrMUqtW-7fEAL+v`ay=7b~o_Osf%r>=&3Osip5 zUOQ|rq@BtkvEFF-?|3)LY4`a_#AdWy(6}wWKoH9N{bPdK#8~TyUE@Zo#Zr8KbF;M( zs)`GxTS}L?T(&!d&{=Eqm*NpMv^uS32`k&AoVqt?LfAt+b&vGaDH)Z5!g?ps$EaD~ zrA~xr$Gflkk52a}s0Ixkyttd3oJI+Xz#>>L@qOD~3k&S4@CwoQp?w$HTzGtqkXQH( z#nF~tSyAD#`gc>UX9^4DxaQax9`f==4m1t@mfs=FVaV)a!TUV%)SP9r;sQSjBaP&3 zS#jQ7MyPs0u6f~ZLo6A2W%Xrn@r+Z{{ww3KtBu37wZEJ_0A|OwQx$AKE2_Gp`Y7%m z$$y)_tm-;s&ZsKu?B#i9+|{pUy3Zx8<#H9*8i90Y%3wcMyS(sBhKjFkHsN-=fB;n! z5Z#xwA_KKDU#)N+Ox15wxMrnnIWk{5Hx3NAY6?pHcKYG;CA+oJF|}0o&HiAB=eHIe zR;q0uvx7EQx>0u6%Bl2^8SP^~27?dVtL@#)XEiBlz`*u(hV}ZIWDUZ~PL-06GgAXv zmxRjrHi{hb(Rm?zc;Cj#O4)fspj5h^Sc_Udh|9o1rl$tTk@PG{3i*rONNmsx_``aj zSKxLF1M4F9Cpw;}Yc=^?cl4{bzku}#^dBLYpUBC0QaUvj?~lCb8qvvsCY-i-MZiVy z%&hXY%&%ZhRJy4f4w{+KTq;Gnhk{XDrlmuKY5#9Z7F20d6Lg;95$#K?Uevm`(QDaJ zX5x?72kcf<40_fTykP5*YpqfJy?sj&=<4ZlT|Kj|~=iL2DAr{ssNLUYa z0Azh(n6MC}$nr;yMpKl`W*2`T6b9uBZg`~S#8QFI?#UV*{5R1wAnbV}^3S@`_>c&f z*xam$AZ=Om>$I3tRPJ`rTxM}^c2L=^Hzr?ssnY^W%SUD1{QS56*Gt9%2jSOg*AmQ_ zF0=Bip-Q#zKyQUAFrH{Bg-oGOaaP{F&>7#{&IX9Rn<%tXFmSu|H{F@lLRIRF@uuX) z={2F!Jz%jtsPcBxj6+6-o%l0NfXsPbU#|{}@%p}XKMHdMmNS?ZLqXVV@IAEeoh=Ju-W609xT}t2Gl-qP53n=w~DB0o-Y;Q z-hf!p{&n_n@r;wx2%0OL#UWVsGj6UJXiM&z9TRYYcB+%d2sNHM4eIXsU5@G~sFqh+O)9HOH?+-Ii)iZbr5*z5 zL!p_bc;JU3cH`5sfmpN`*ICm6K#A^L({7J|rJM`@&ot{>L+{OF>HR|{_=7jk&v`-; z{{WRnk52+cmstMSmw3XI>UeVMSA~iU^v_=mOUFKU_bV3t2%Rwk4Y9L-WOY*q`3mWg%I-vZOy?PmP%XMapWHPyvdSzc$H6s0||M;yrhfu~;Y?|YNq>J{t zL;UTIkpulZ^JRlKtS`qkc<_7WL@7_*`ZT&QlLvf()=0kFVHUO#`Tlx(8OjW3n>`Q- z8lh*q)WdRtP%=eQ;bB0lIB0R*N5@v$RukP$s4I>@|`T7iyKct1q%3HGXLOCf_y(U0HKg zYPWo{sTsfvGT1B7cK&nejATqOml7ZA*)5FzaGg;D zc*)y$7dBH9hYM~URyo|!9sgfguZVXWec=M(1UagOT@pUDY~~oda9i>m=VZ5T!ApI2 zt^{V;(_`S=_clQ;y;KnZi^lJ9ixeONK{fTe@REJ4PUM}m3V_Pp?$B;tzR-v5?PcT; zEzbz`D_`$6-PqRqTQE5lv88%P{?X)>UIz+UEPSK5;;xtXET=TUNAxf33yVO}5N~sY z#AwFkifKoUEFDB!ybwtM?ZSMV|Asj%9s#sn3-A}zDDxs>SNIpqs?QpP0n_Q^w7ZEM z!W_w7TrJZ|2zR^&@Gp@;E5xmtSM4|MB(*ip>gXCHK@yy?7F)iZMajc*rda?-_6t&I z=&f%oF|K6BvGe$kKW4-}9D#7IpWtl_?Hb}ZHm!2&@b8ku`+2Kjj1mF0H}sc>9LhPs z{>+}<6)mCU1Idzg#V?gMB`c?mRZq;b1Kp%Hx&oV{PEUTazs3L}c4DWu)jgMy)85Q# z{k<<}RMQh6Oy}m~d*MdboD8t0h5l$Vvks;%wt)-C*gX`LYuuH`J~0xSG+)C880S-Y zdNPC%E*#3Dg5>#gvnN0K8Peh%?rR;kHg!ekq$PfUmM}-IQ3AwMW2rJyTlokID?`A* zzBA31Dj<#Oju>zOFfvMt8=j=KmI_9+^RH88-&6P6_|A&FDWc2#>`jG%+V20 ztLclA!s-OtrN^veQA|L}U;-TvDdG0Dc-r;akYSQ!0-f!S=6{jmP0@(?uylP;+92J) zRT&SPU5a@u&e#@y0RM}F*W`NcDhe~s3GLJqrjK>+9?YcbVM}7A*ve4?TIHUQHDX;4 zCP42lENdt=@lrSz*b6o`UvPG702%1_PA{AyUpVv-v!&}#1${N}T9dnQ%94!}lPY%( zFL<5jK$X07lWm53+GBv;xH@15rRBUEN*{aB0O;%ouPQN*g^<>z(E38T3$9CXe1pxc8aA9q?Nwoduuuk=Xh=oNPVP{}8P zR;T+(EFVZrS{{SL$8>sI)at?*P5CLv;VP_oBELkC4L;;A|{FQI-089GZ%3b)1>#gwr7o1%@ z@$5O<;&ex+Var1M{amw%y5F2P8SF;*L;yGIUwm`P>OsktFuRRS(YsZh!nQEv<^TE9 zg=^Wv?puzQtxY3P&-qtw34O5e!Cz2MnKD^--xDvW|1p5?^2b?rdpF%c8c0W<+`Fkb zj2e>0eFhAZfqqH9$tA7|%9F9!qG<6X*}C(SU$8sleYhTpppoV}ZpT^Ysdt~AdhsjL z=G8v|fA{wpF?HpiI_^%AqY#|PU0izU&lEWv{>P-4F z%{5ynHCXQpQpsOWlFWDsV?K}yj>*H(xXNAEx{3YSYtXvn4q&E%$V{JByhDUpYpkHu zqZ2Q1aT7*tb@uUuv!1tQVYL-`2rn$ut@%s;QX{pLa>sbhRJ3_S{PuhVncgF>#b0=y z5|)Hg*r%^KUk6A$+T!Vqf4n^tIS|Xdtp7li6*-IRM8bA*tAgtX>PkQ8(+|lqi#Bm$ z3^M^nI0Ed9|A3%FqOb%SB#YL40!wk09`07|{Q4p+f<{LfMQyQ^>8SeWvO&UQu%KmmYzlbUwSh7E1J z6l~EBFovu|S2uLSbYYdeYrWfmS7-z>T|D~)SquQ^GqmNLqebW|u0O9=N}HQ$Ar7jU zHML3;EZ7CHHLn*w*O>HMxYo9NRiv8BMSWC=AS{>EV84@`Q;q1vz94<{5T$1=Y>1d4 zJB4f4U$tOY^4uF6bnMo(P3Le4HYB3dcHI;leHc{z6=vR#Gu{cG0Sgaj;9Lo3A$1ic z0q*(rZ5t%MQMg+ycLits2w?&A+-iYhiw6K$XK?xle`te0QRjma#?zpibK!aXR7ymD ztovDm#6Tnc>ml54?DXX7E&;M5%=bY!YsRsBbxmLJk#uOq9MV6FR?o7pzGBe+_0EXRr3K-?3@b61Vyc<}^WB^vkVNmPAZt6@MNY4g|O;g7o~ypHt6f>d$+Lol|?Lms7-* z(X{a^aMLtmdtHM<_~VBA|Jb;dz{*x1xWpb-SoTCrAc$*YQuy)%q^cU0?b&6*N%k)-~1Vx@nAGng+1 z;zL41AfwuTVdQL87(q>VS9(oGVH`Y4^$S9qxzG$UM~tv<`)6p(4t7(e>k~ zO5Va1b$_FaA~M-0^3PBcOlSz9b&mII?AxT3TIilp4A0#vXgdecBt%V6oVO4Xo2`bM zE>X3>`PAP#>)(W*JN0BTbm)Go4@iH~!#Ie3sYITQA0aVNZaEYG$egZwV{nJo8(28 ztPoeA!!#!*4#V5~O_gyMfpcz1^_qBRaQvHOA7ZivS6=nweuq(IQf3_Y?c$76jF07Y z$N|*rGNQEyuP_r+zTA*|8d%T67Q7} z_1STyU#R6(QpyQf5ZjB(35?>qBG2v>2}+fIMG zcKNPqpGgCAT**5b#TfLyB(b$S$dRr0lT9qAcwA+~IHpDMJhX#9F&b22B=|JthcuzD zLWf#1e)S9luZp3Zg>(^j8|?n@WyYfEj^8c3VThSIjp(+78mroC>?D~>uF-Nr*UxeF zCkhN6M_>&gc>=rMdO`#px;dQE5;?4k3v@Al%J`NRqX-T@V9R!FLK1CE8U-?xy(2Wi z4N0;?I!LuL!=xn_ zHT`U1W>;tc9V5u_oLD}pC}3!9nmbs|M*(W;0xD#oH0DKFr4R5%%8pqK4auyy>+4yI z@0Wlxur>*{WnMJkWB@xft9d051WbAfSws=18Ljv@DSCS}aB4dqt(G-*`*Xb9X(rDk zPUXUcNZo3VjSfc{RsDPDtv%}g^~dSW>QTCQ5xW1TDoog|yCt0^fa4(aTV8b(A{bcW z^mA(jgFxj?yUk@sYOwzv}vovn_3kO26gdzFA#P(9^VDMf(sTODDcoYVmK3 z=LUc8Pv_;<89Wm|Y)!GGa3QDaDAy^Mp$>&caTsX*rfkAjaonI-Rt6rr`#k+6pqYnD zjU{J}#efBKG_Rgw6B`I-$+rMcMQz$)>#WVQubw7< z*9~5kAPKdTwoe4mg-2ubMu&Wcr*=Lv00D?p-3C1R#h|T%_BCd7JxxN=^0x!kWWJb* zwRTnS(+zkZ@MsPAo|TUfJCABH%dtfOW}|nL_EQeIt=RXdaH%QiCn_EE%r1NHF<=%) z@0<~*YgGr6gDue~CS5=g{*8?3Zca_(*Gm6U0MX*`Ysw2cx78s`hm<7t@SrOL&ewHDZ6EFNpbWxpQm9n5KlCeCKYDjIS*>d4hVS9k=WB{B-L|mJRfs%dWVu^?f%xXGH$ds zfBP8#%RJR&CE4~})*`I?fsN{&vYs!<9nGH|=lDaxbCyt(46+mpe`<>TRP_unt0^)w zao`f#bD$ig zy};8utsnb%MknigKvzeJL~PPTblY_Jl(>Pi`G90u5|TI!rYB|ANQ3lHgJII`<#DFS z`s5=nVqxw_RjHN{(&rB?XOH^KqTU9L&Z@>n?kbK%4cH$*>)b!|k)!B&wteb6{By;` zp#1nKs5mdCNNYR%c4k$wr{O;5#Z=8|4uU1dkOt`&J@h)eIevO-W=?-@pPUM(etah8y9ZNrvKqXW` zGg<&TAT;nUjRXquqS7VEJ{Y6OQFnzGr~utsoA^J}PKG zkgAuHYgO(VPSDAnIvNQmLeiB6E5Bq76&?6H2f}Ud@4*b=_+Hy5B*S$2RIxM31^mUH zi%2PW4}E;_ON;jhvUz!5D95OU5prCMlP<5Rt{=yF>bq?V#ynm9BWehn_U|M|BxOIi zcYALZXo{O_{41V+Hg)cQ;y5ZHQ$9q|{iGR)U`l#bR2}@Tpm3pYlO<2UaU$wxSA)D4 zH<`*p8n9~vtkRbGvl6iQP~|4`K_^Q_ond4p)t+Qtm@}S*$&|qGLIB47LKU>%Wx)ba zBTzjv_8QI-f;;65EHE|rEuOYNQPS9LrTem&lQX6yW%1&o$t@n6l1)CSzE$^yLbPx+ z1|wmAx%cUz<7QzvTF?n2h&}NWYc-I)H9$R&{?p*vzVadaxPQee@u+ z%6sU6CRKOP{f)|QpnK~TJwSIhtN%*_p?C)oz8mDW?*G@#|2q(fDvQUqvK>0|cs~?i zSZOo}cM}vPrJ0#!L*AhxBZ;l*K$1D4mY!g-IDe6qnc`1sC;<9x=VcSOz}7yYdjIE) zlnXLpgVO$g&OJStPhOQK&-r0?DAR!GN2(MEr-=}Nq-SMtlFNa;2h$}2*_-d!7Z8u{->g$f zKO~tF=3}h|&G1LcSOwo=#=AEE+?)egnP8erg%nShU0g>g6XbURn)>%F-+4$$Fdr*~ z(;U}Xwp^jU7vR-BQkZ?B0zW>+ntqI?dfK6vddQ*#Py?w)?*o5mV$Vi+Oe^n`ovf6M zTezC_5E*Aizes?aL+w-y0Gc39Gk^y;z=@mRVX`-iF!MF&C6`N1S{gD^S;}kvS#`zI zBMU^ql8p)_>PDvQi^`v+42 z&(v*j%bl~Jz_-*gpZQ_e=5M!+2?=5zHfM_NNesopiJ4Gr96efV6L^7fmW(!eyaWIM zK^TT$=Z3qgRpK%ib`(Q|LgJF{m-qQ1OJ>0NA}KLxv0=dtShMru$Y>7H3Mes&rbUA4 z!@GSLU!eNy-we-SYRHEt#uEng^d&ojI5i`8@Qga!_-y4eCyXZX`>Pl_k9751007J* zd?9gV!-CAsD#2!VV`}O2DlDl;bPX?^>ZyQi4rh~lam)qrx;>R{$%#o^Z_YaE#yu!9 zJuy1cZg_omyFmvp)mWN=6d`B50~i(9A=NExSaCK%0R(V+IN(XZ<1PRIC`{g{^}jTZ zhE@rxQEZAEYA!mRsytJLd#l0#E#H0!%}NZYI7fy!GN4MN(j6FJL+|UWDbxJE~fuMM1|q>FJUF zU;O}EWsI`Rpa1~StBsUaH+XxHs~Qj{>w+N1?tq3h5yn;Y_huAUydN%Wa0&sn? z%gsg4ip-z{81J4ZU~tlFw`hYLvG68M>+1^T5?F9tcv@QR^q2a}l?VhzVs7s%=lS8Y zBPVHAhofc^{p?wOOwW4|Uh;0tz*}k^Vr{khKQwHOcYVP%Tyyj4x3B)1iTJ1V3}`;I zg00cEQx`&|`6%Uw;)|ilCQzyD)kt~GnSZQvIEKSM_>vxA*AR}a7d_BtXf$GUEb**q zGx>G&s+lgRmWKGRu+Mn4@b@*}`gAiYC3^=pjWjp)5)}7CWo0^qdFQR3n$`}ewas%# z{i1kW%Q}CG$K`!I2$6ytVC%XMtOLa2XWJ1B?d_%-t2&<*Yi#9AAdv6yeMMm~Ggdi( zLUDN4QSd+Guum8ZpjQV?|D4?=!S1+~ZZ}1DcxaD&rM50&^m&PjSRWfVg$1@O?eX=O z#={DWcd1o?4o*y4C88lFJb04MQF<)95q4vB-gVA^aFl z%J(3RCmnsk_fz*NlU&*#k0x#drS?kCaiOM~=%gg$AejF{V**4Bu6>4DLBUIFGGR6N z^n1aEQ-_ww#I(TT2|QA!hP3Ovn#+>N<5Zg1EHTzj?Zr_Q)D7Wk_uzf@`R^AO2RN>u zn;NA(w5Vqx8jF+b;7+uczc+u8JF|7f@x1~Y#VZBksc^SmZ229?M5X>K-C-Xmjr5qg z&bDMC$Og%p(1X}Xtvk1Q=u=)lwQSxrsiDxNRxv$r5e)NJ8k0G52?c_gbVxMd0vd$2tqv1Tuo-P-QE6&s4#elyGr3#WY zY0?h=IC`2*)>ymefhDWN#SZyw+SG%?us&#e@B@Y{p@yZP^Ci`c_FTPv0@wPRbH5u2 z0^X^=1_qw5>R|f6IW9IFLAP?^l^maB{b!-AI39`5{HkyIty0OH=SdCA+xCb+RBDIy zr0?aH+MA8G?>x)cElN_7uOE>iLu%b+{#m&9k0AzCM7fq)_eSAEzfg zC8xeAMAONlv)X>=hfo9GiXxu4=#twK!4d1vY` z^k8szXpkR_^>nbwqj4#8t1F^TbX8joWZ?etZ3p`1G{w4?@D}kF0k%-$T>#{Vnogul z-wcnkf~dZEu50LymFocoBl6w;_lU?j6|59Vp-7S+siZcCA}JANY-t1Uk}Q0X zJ%|o3Txv1+L@)iMw~Lvt0QCk+cYIU#!8z=*)*82DPMKHiKXWV4655t7w^y_g$dP|^ zaEm!J%;jWQHvcUYT0={w7nkr-u<%z({INNqnQ`3ZCMoE|O{MeT>?4!XFRgUL!#V-* z-R(X4ux5zG*g)@pGH z#c;COsAmHfucA zrH5h_V|DkE{YvghRm6?8HP@XAtM;7pWVL)s#d+)S2`fz4WAF>(JzYhTl%|*S=OQcg zvfchJ5%lE#Ym;LeE9xBe*J%Rxs(00QZ%XN|GC0I4$m4ooCXAteGeu&!jh)kUh9gYI z27rrpCi1Z*P#{xh=}Yz!lg6Q^>>2hZBq}VD(aOkozL8fa2XuRla*#73u{k`D9NG4F zrd~}R5(&U+4(v&U<1yNU{C*1$U(B#;zlStMH{h+@IqINaea9`!k+%@q7=?LKTeR~T zp`3>+SVkHc-}uY-L}NkI*i$)IbMBOcACpw-nCx5()x|tEQi)xPvcX8CHF^)~?+kKM zWMl~RwzJ}6zo7=S$gS(r)xW8^ehyP&P2r!+VQT+}G-7X1EPu*4nEzQKAfJxNO7<+e z!&24_?HPPyg8|?I5$t9?j88Ld>MTKml?JkLk%mBmA~Btu+V0`63Y1+2-~MXnA@%8t zG502|w>vgz7UoCo z^oGCXUatl*eu*3tuHY+k5j|OrPERC2R29#%qO0@$ErV$iupVZ|`Nd^dLs`}7c@116 zH>YUCSrgPSe=M`OR<}JpDl+)=uzZf3ozJWQ69&VL8Z4f)xU}Gb1xU%~SYeJ4-=}TE zn4z-AV+<{O_hCogUGKj|>7$}#h0~GVKJBf2nsoy;w$By+Vm&k>&1pl6qyC2NlA_2S zv3dE2GiwOp^N22W)#3>>hGcDrP$~i71C4WZ+HVvM`Ma1jv7OenqXc&6b*Ele^Cn!tgyxj-!n!du1Znn5Jz|vEp`jtS!t&-GGjlTb}^Eu`eR0v z?PG92zKc|QwD7V>CuG2I8$`ju%1gV5fNVKM8|Hy-!&n;KgCHBpl}m9YZeFG}_FO$k zbJzF0U^EjrssLkZa#=549QClB`hb#QC^o~u%xLmMRnFd!5h55H*!q)10xsRKMB^F< z7eqA-zBnPed9wWt+b}Lkjs6?D&{0!ST_w2aCevait<^cg3bxT_lfQY0eLkp)ZsvH1 zFSuaDfsU8*+n9y%4EYks@|OhI$0LHf@|Bso z4$8ecd*GaS1Wq}t*B&T3jG9c~7dZV;6ny~ZQFR5U{f93IBc*E+T~OQls(>Umi=f2w zRnt|mj0_vI3f>WEgnA2}9?hM9*^CywPI{Zz0Pt8tb{cCr$Y*56v!o|anf0Ee>{`^` z$&kM|{WF0?PyS{s#_cb*`$@?XiKkk((|3m5AIr^=&-mF0StZsxSaRW|r*$A9CAI#t zIuO(k$NOv&NKFj}B;a2LJ0`WK-kW#58@wO&#rEFneGDFzUm8epSals2X0sKzr4gWhXGeD>(T_s^a?x;51j{dmG1?n}F%kEJ*!L!H5w4QXK(`B- z2riTnxCL$Di?_op8`7G}v!%&krQTem8FIZ8%vxrbDyH870u~_M9P>0cd(08?1z|yX-49ak!#o1&zE|tr2 z;lv`8(m~OG%qYDR=P?*mSksE}IvTg+E><=w58ZOf{>gfbwHBt^nf}AjlIYu%=2EA@ zk>#h{%-4nWNU?x2y!(+~p$LR>1uF0O?{E91@hWz75N&2bk0e*DtOcWSJ5Cr%ykp>K zakX`YKDYHZ=o8-9fexE0Bv-gNLI96}28)y>oEgw(`U6C&d802ac z%lp`Yi@Dw8Otsar>YLP1NZbI2Qw{*K^9JPbtkrFu$(7QEWqx0Bn%IUY`tQb^w9gYU z!-~5}9ZKBivdaO5@)Wp8xXop`irX{3b(Y>|a6l^NQY3z?C=OYDp$zknH+jk>zXIf) zcxD@mnCX?F{RR4@((u9eodB?5;bZND-%3x_eZ=Q#W&rNj7hL3slz2LwNw2iizUf%! z&d55KK^6k>+m|$USxG%SMVcSTrA&j`+5ND!UpN-{zW$w%zgTgDgLW zHNkcqF_T~47>I)ciz%NrdX&f;K7uB2;itRlEI8wFSk0b`1Pg@^2R0Z@bvr5 zti6FYmv8C0OL|z7*`;oV@g;>~CZ)=}X;9;~2=(W9fPuF($CD9CYkZwI0Zkr}D z>lEo#PKkm3NZ80La+WEcL?63<-F>8-sJN15iJ>S8qZt`sO^FT;UPCqCuVPtfkNyLG zPUCQU!5u1mIt!0f$b|&MrYTl?RtAvW-M$BKmi!&5aPt2^7J>Xjuu8M0%h6Y?V~yJ$ z9O@}21pc2>W_3O$|{Rrm+FGLIh*X=G96g$ zg#HU}BF&lly^mXhbPVjkETLL7)EWsR?~fs+WFBd>*|3SMcp?$O=S3hurtMr|dwOHU zK^H`>y=dqW9s?qoD40eUT-JH|%!AK^V`=_=sNTAI4jM5B-76?G(rgd(`{A^*p2J6g z1Q-GZ&NtI!JtC$=4R8jdG@N-PX*7|#zZDRoH(k8?hWGr-Dc(izNH}hT7^MDn)0LC! zYc7o5Ed)to9{+nMf9Dbo&ix&D`@Tz({zh?0K};VNV&+)813+~bA@LXx=|E8eM#nQC zPGrH4|21*SB1SfbQQa|+Rri~V5r{4RI!}I1C~MG|_bE-yOgWEo)W=P1L|Fb;F4i=b z@4U%k%a+X(b($NWAvAfuD;qrCS0I^C48fhu(rPw8D+AfckBn48Q3j1$dOLu;js+A> zIQ+NHH>7hb6i%)R1p)v%q-vThWyNgR2YvncuVnXsx*}MNmf;r>m({ami`iu^5Ab|# z*MGt-tYESQQMt>Mz~dbWD#NHfLvPD}qk-3Ef&}d#!SewSq@hK~;r#({LPtGR0xdbe z0I&uClq2rjrZZR%7(hCjJC`Nrlk3{zIGxjm)f}AwXdQoXQ=Xz%qh6utBScM1b-SLjX(@iPy3%U?ee<9c ztU>Pduz`S#(a%+C@#rk#-4eA+HYs9i()7^kJcTTvEnE!vFNTXa_zurUuHIM+ni8Q- zA%Z29eIfdJcu(Cx$%u3~RAYrGY(Wsy~t0ucYcTBevNH7Mri?~ zU8b7I@!){NZUgoqKw#*y_?}c!!kMwBImB=A0xGJS`cp_I|~&R+x01eyc5t+1|Wtg=~?lyjy38|6ZgFRDwo=cqwP1sMDYBzY&B;6U=cOAL*O)V^#ld7wR3%pe z8jcHGR6-Jx`(9HEG6i=rBQX$#0Z4G}WJIolfpn`cz})SK7L*mCf7NBXQ!OZ%O*6U` zHU}jjHCDZ@XP|r~MVD-6FxdUt)XMn9j)XOlP!!+zIzeW*3Qtk*I4w&dM*-x&Blb4Q zBWeQNq~CuW^dcRdm3cj0O|<92jQ&UfD=L`CFwzuvMBJj%0Ec*htYHX#DYk(`YFC}@ z*E1TLfe$hCbz2y@j(_va`lQT{emX4Z7>Bah;SQ4}}Wcwyo|gRPo(JFU?t z54)PNZ$UMs*CO2hT%%3vYnhDs=Vz0GQi5Pte;t*nH1x45@Qpu1z- zW^6;Ou<)%8(ji>it8Bqzgh>5Mky%-p1rtN+c1Rsk&kD_Uzf(HViPIpU;#M5&BdYV0 zoduaVGP(ym4D<3a)e)Rd{K}vGTXT6o^~+vCE;RzQe@e{_UI>s~J-SI}2<5AUNJNAi znfejq%#qeH^Cl-p?Nyer&G1e^VMO8a1%tKa_s?t)jOkX08+ML7=+{fo1iuGg4f}!@ z@+|s`%Io{YaCD{cEs%`==9impg6O@KetSu*h1^>C_v@y|G~UXe12JO- zb{XKnOJ6|Qd0v;@-XZ zwIY~~);~rme!+S1*5^=`XEZ<&-q+Ox5K z_(<#;%6X9iIcxsO#d}ZCDpUhfXU~x_GrZob8N^N$2Zc;Dhz{O95Fyb@s*`AV;l&WI zSq8~#D%sA|Repy`V?=iWcA}Hie04LHuJm&t7DWj_`2Cg~I74;nM2L~iO+vc6?glMC z)vk2cmqHaqeCWu+t9o15C=Ct5C>XQ}0BHw2gmmpX05algb-Q_fmoU)!5~2TY3&sGmo(im4F}HN!7nVICzgt zeQS;;D4;_iv#gvGC?Ni9Bk}9#l)1Jd23H1T7g28TH<{+3+v^Rum=2Ug=Z09y0Vwpa z2tdxXj!)$^5LhIwcOF=wvrG6Jm1R?-OfCJ&YB6VYO`NoPf69QWCg^M!GK2ZAg{I=k z6v!H{cNGZ$9GgSOZ=U~krORr2|GLJ#-deqXw!N1+ll8*SX_U(9El4h;Nq_TTN-uk2 z_sh3cfdxEKBWq5)HHo)^oRvLgxK+$!zoSprw2St{#HR~iN?#zk{!rHfgaUI4JFo2> zs`1+SfD@NkAk+1w{TK`?FXjab4(cPh+_4O_(;C4H=#_w`i)3pbrq6Wc=zHNDzb=1SM{y*{sX#Ilqp^~=?0w+L?FauIns`6 z`-J&M=1Yt7b0^6HvKbq1!Bs^CZ7n*JPIyX=CjTN6Pdc8U@?~I-7h~Bq`6Uip7!JAj z`!$bwNpOwW5icsvC$zAw1 zfpNaJ%$A(0Md~+(*zgm=u+G=cX!8@A20J6E^1=cqwxK!nmt>gfc$V=xM}Qt3?P<8t ziq#0nzY;(CQ`(N+I}vhS1UzJ98a8DUDoX`TaAUwO5JTY1jSG0M5=Q;}Z@QwprO4)% zn8VWGx6UIqGrVlHl3HmT`P{DR4i(bolEP0;ENRpe7*gV_Dxl%#*?nJl#^$YusV`w; zyZ=OBm8G&^D3X*+%S^|-5swi*1+c}?-UDUU?lBr~QY`__5QlFYwLJwOlD=M=Eo zkQiL=*s&82f#1a)6ko!_16*12G|wd=K>*7iWJ zXG$oa&clUGGWxz#`$hJ(^QggT<6=UFi*kh5SR#|*Wv%ie>v01G3g>74^^~aAA*Qfhh;Lh=rl6+G9PnM% zUik3jD(SmH4g6!hfdLUsZ+ss%@0YQ?lK7DJ&qQnzFB|IrXZulb#v4LIpbq@iAD1W=lyZcV(?^7pco9*Hb3S1bKAU{lhjOE*}FnURL@`U zkaEhf_i`X|*@4)->1IPPNiYymFlmgsL~Hj0p+A5Gm9a$)3J6K-qNduDE*IPqKE)!Q zL+IzCKxZK}T*fYB&(a3mKd|z=*%2*l8lun6X z8ucvx)gqY)Nmv;~Sj{7U<2JFS&&DcDWLN#3Bx-9XN%X-jZ}X*jikilFhC>|6h0vYn zvywgePJe+xlJgxjR7Qa`IPPNyPL)EC{}^`49(gl+>;_h80$Jttwm+0$?B88H?m8Lu zp(!Bx8cZ>SX?7#@mdC0Iq-L4YVHgx27}Wj9hW`V?d&=yh5&Inb+Q155%c~d>Sel?; z^&*?yyNWiBJj9&=Cc8y2cS4p9c|tSigoYYpifiHxz8`>#SpDIAOSp1{s9LV&dXy;! zOY_}xFHF~*31eP*l12em;FL-2Z|@ta6pDyBFx6?mgf7hj(_@(vAO$@{OC@Hi-gi~a zF6^dvN)&OB<6+UMYZNy}Ystto7lumks{jYLo)n{m`1b}Z*Js>SFOX}+m5!Uy&864~ zb7b)uz{_A}M3IA`Bdj9j8vRYN?Q+9F*VGFChv; zo<*Er8l8a5^n?L0EOFy0iWoT@%k6*lP33D#woqXIiM=VpVIQAVJ}z|Y`MOMBzc1}I zi&GhY3;;MsnN~y33EuqwP5BvLi6okO0T^8z;nQgT?HdRx$*yT%5T3{dU*Yaw!gR5D zG~bC*kzy@Q5%4uF3~1HnQ-sDZlTbB=AA}8In)d*L{@z zQ~&f2R3FCHCZ{S@JOqa4YCCie&MkxQg=+)qEQqWnh^7q;Z|S0>s*(X09Q zfc`dOhG%Gd+seYlEIkr9N-f3fD!&ED@h{3E1im=yN35}LL8cX;embmQ*|e43%;ss* zcUzf8KZklS?calKE!K0}eb~gHN4wHetIaT=Wrf&X@RMNKRpExKt=OoLc`+v(Up8Tk3`|ZK zs0%d`x_8LbMzI&eV)S&B_eo8C9nLpGwSDsu3;f6m;z|Wx_k_{iAk*>6A~HEUAUhW* z3p>6v5}AzST!;miaIe(ffC0T0#NrzBW2Zb9)^#GPxX+uDWUivC+Ie~yhT98D9NFTa zIe4*NI;D(kSY}SKNwW`&_2{+Rx53!IoRGe4e!+$JuDQG(G5%14O}GZPZ7ja2A^^G@ zvL1TkVY^BFOdIrcQ$%*1sVRwCG&R^X=sr?CA*CP`7d|r`FTRWynG>DQ@JUPm4Hva! zpHoC!A7|8J;OpfFYd)f#AN}*`P(WE|imq~eMBb6Ln;3-Z7!@PuMbCqcm@!fj%4+Z1 zRNdNWPM6GLvO33I1%Hp^HgGGx(k>JhQo1SV-guzN=M#jX=D}r1)~nHw_KB;R%%0PF z9$W5%%-x^q8Ff7C8R2)b8`|lZB#x9XMbAKr9p$0MJ==JA$j_!JuKuw&2a{ZWzL)+nr(J>wnkW96~vY)-d>F&lGjk9BNv+TOI9EXJHlgFKe?aJB6=d%1cSH$Y4VHr|_vqooX zmLDBs@I+NPKCXk^C3%KZbt*Yg7>(6@U7*nxU&5gU=j3fB#J^0}NlyK=_L(lT=8ad| zf(Jqcq>lu*$PebaVF@(uf|VISc>CsxWfA^i-W(W@T=A$fY%4>>6FsabRYi|Do45h# zX!YDGDtOYHKo!%r7&Ru8b}`~Jlk$NI7`Sr4aYgwR=2@D0{7wK&xbRa*HH41XPqYyK z0(!$zs4MDuN`M_s6lRiv$cB>-@uw8*~7NKgZu4@Cu?&+U#)4bOsFz5P3ILL1G)6?t#^0-w zRG+9@$WZSZD{sqoXvcL)feV?aP1paBQXEc*nE|Qkr)G5H(kjZTmrprlc4pCk-d{6# znli*_DUKmhYCSrSNz@o!=Su3eQ*?Jy?=ly`b;iXe0aPc%v~TIN!Lx(Q2+;1uCc(YV z{Cvajqzx9)%rYRMwiPjJI`lMbEk=xy=lNMYZ<7wu4u80d#}G9`2P#u|TmAU>HJH9! zsNP0YR_DPPI0l(kQgYW4bq=m1k&D0x~~0PS+}HG+-H zMs z6h@7-c6+#z|4(QEfbLQR47HavuUTtrb-LeZRN4$#F>%F9q92mG_@0w#e1SAj+`tQ~zl)Ss9)BO`6!k#Bx=3 zOm;*(#zWjFx)6tLRU8dwC+los06*I&KR>W^1n^$>;ktWR1pEub6^n=|;ucHLc0M8Q zQ>HKDyPd5{93qC{Y2(QhA#h00nj9XJNCg!*^*TM#buM%vWhD-NO)>&6)v(*A-iFqX zphitC^YF9Z7e?C>T)s8r=#0+^P%=U~5=%MtQhtl3Evje&ex45Znto62(2V^oz-DIs zrE+L?YFA7+a4Y82OJbAk%b=0vk(V1$^Jpinbwu(65KA6zN71jHjwOUJkU zK0uK0{7WAERmanawn9jEV!k3Crnk{&LKu=tPy+LE73&#C&)Usbr0DjqJat_uf2f0Q zNr)J`GUCK`+U^+5!AL|W#*IEcuh#lT3TSNw)IgP%AS=LJUG`XU5%&`=h23-+(%`Qo zo@Oz~@}n}79@ud7bvNrg@`nLh1ItK00d5FPSw^8yAtTyEwsKixa{{Hzd)A6;l_+Zr zgiAM|xFC9@x3=G_iMbC>^(7%e47{OnrMcMmw?zC%M#Wy(ZgF?^+b(P4=TU9Ns-%ia zzV}zrGk<3n0JwT`bV;N6*`4z|ib-N=g1`?g{6G2d(NV{x1C?g}i^{N3BEyQJU zWM_KRT#9_%DH!An`6T~3<(U$$bJ_at&?@cs44S`tV3q7DNP-6tV9zwzx)JFXT-bR@ zKUsF|WDq;jXQK0Bfk3odi4C@J5KN;f@~6mMv*dpd*l~hB5^CHyr8Vbm0L@1Nm}dO8 zY%6UGaKQ1Q+QwkyyXEa1;L(QTpb4zHPja~Ge?0+ z2Oo|OiB-ndlh-uY*pn*o-eWI8l!9OD1isO-jm)ff8QRz8&95q@IO7*dZU7x?Plam~ zZ%m?-Ll>~^SZDBhR3|}*SwB)O$}%zFCSk$6oU%zTY4!%^NvE=O;$BV~m4yX>s!wEh zw?V9{J^i%`Yx+sGN$+tMzDGRRkQVHan5y=M;uy4(if$q z0ISYwAU037l({K(rsMX;Te)P{Q@Bh>2)P_rZnwOdue=RCZQHql?}#_$61O*m&<`kY zP5sE;VWK8sM~zcqISYb;?=SV8v2E5GL7);lV{PBLH# zGfeC8mN7(Q6isN0x|^H|Jv*SsKcq$@I^z!N>%O?7qkGL{t)d<+SMW)*B^6vwW!K)3IcPrYiFWsQY4!=d#QQ-Xrg6^I z!vdo5JM^AD^gwVbSR~BE%@pKgb_q)BqTwJfdlD3)0QiMy%uJr|ofgbqiIcBUaE_|g zulgeU%+3hyhc%OQsu^3-UWgcXw-@46qV+~{>3962InN30!vd>9i`HZSS--uqv@**L z)u3Bp=}n@*2ZY@U&4a0zbCUO&3{YnoQa=zKg9V^t1XL)p?n@=Xb2KbutvzBxTKN!41ymd0;! z51sgYpVo0Rew>(q?O4H&9Q`wzLqq0aMYLf*|5hk80cPSJ9dk0Z;|oSJ0L`I%rECX1+|RjFLkh3Oi6m$_wL)p(Er^VDP6F|Nw~ z27>Yi9J*L0`?4r`USd8+a-uUI8(F#$9&U=+i zCsI$>U$-9DxH3=XHg?^*9ftQ~e98uWBQaZ4NmmH8#DRRERyw*WV%GV8q%xl*J} zq|NywJsZ44uQZ~LxjcQ=8RVl6vd@YwsXB@wiVG$>ymoqE;Cy4N>Q^IHdo6ve&EMuo z6ds3JN6XlIf`)R}h}q?)({?*wZ?%xEbW<;sUpX#Yx-&%IS}kN5N}sus3juLoRDl_Y z&qhC}k!ZN(G=z67n^)FWfjoYTs|kDFM$wI7Q%6=w-=&tUvaiLlhuS5t#IRlb<{v-T zN2(_92Zaj4xh(l1i6WgAnu~um?!xLPN$ODs4HHF&X7syz;g80Ww;iwzxuwPuH~wE9 zYdB)B8n4^ue^lnQL;+H_NBj(N4XCb1lGRVQBEVX|5VaCIPsHHp(PIXYbY);RX|XL9 zjrhs-nw*h1z-^!IJQRfP$}V|)5FXFS`lEa*11O`5=;==y*6f#F&6VcoO3Urk{a@2- zdU|G`27N#@6Jl3{Nht5K3#ZK>7|YD7Xs+9+RPAvq2DrO7y3D>D+TI6^`YP$*ne>#n z+Sn?o_;5BLz>k(#X!7vc6FO+qLn?uvm}DHoQ3x9Hiic0>juxR^$g0ubpu3WNlMbq| zk8dvWmW4e6cVeVZD|d2~b@8oCrei?-s!3l>8_44Ch?82ZI51XrYWN-jF#Ts}hC=kA zV>u{*P9?qDR%1_Zc9>H9Qj)Y>SzO|?09<ZZZA7IZLM+S(CnFuoo z?}z#%cDtN4h&2=_^pK^1VC;@wK0?4nR9%~oorf%%tNu~D!2L#lkORDnOoZm2k{|;= z8YLC!eT!=f5rnfs7Ql`id$`!z>F1#c3L`Qe?z-nt{xW*lEQ2n1IB6PS)w8_iPzWLP zAhxxA_vnyQNzubD`n=Nt80^@TAS&Y_W|qSk7Z7rW;gbN1UFh3o+^$UD_w86{NaCir zNQZFrPISE^T}RSLi<<>jgAb(M;4?Bgy?e;cct3AAjX#PJ<+Lbay}ZP}D2P(37<1d= zaZjpb$LoC)dc86N_~Okf9qS~5#C;-r!}w^9o&5Hstd~^G}M$7^c58&N<4IJ4F>6SaN}H^N5+nK(^<5Zgvg7 z(?0|s3;&Y#y@gBF5ES~5-ep>7U)hP4+F*WmL^$?{6=Kgo_Db)v@Z1i!+g8QmSO|oP z2)tsX@2`2^xV1))(L1_n4^dTNeMI`?AcOjdSMXIL02v4WZ{do}k5`s0)9WuEk8R+X z4Ku8z=#9d|$vE7q8xgb-myZh_oynY)4nsCyK;XR`I7q5Cw~%7M7+v6Vl2LKL5s~Ah zQRxG=jS9P$crTw`j`ol8LNY^QsP|cCIklL6Y{Jq@FHJs~31QmRLCYvndvf@Q(~2=6 z5ihWZVd&K99dLVge%&TI7OXFC&2N@e!Ggfc0#;4E{5l??c{=#6J28wM*bl3lUIY^u za}J1Jors(ju5(r<>Atd|QW71|d{{YQPHxnkT!=go}lxgH`+a2#nh(9B|7 zffd#e81>^yg8VL!NfR^@80(<;2p~-_L_-#xjMuGdOMHk#Lw~Z8VW4B4nMfkqWmDO* zHjL#Wv_QSqV=`O>&oemOeNJ^ztD@2KN)wIEC&ThC zcJ^huM^$rl)#v%gaZ(+bC>`{4y8Z|rY&TyWyIZ9Jk7T{Swi*EpT42#)^2FJ(~wV$!Q?bAIEngEj;Fp>haAbOm)cwcLC3CG45q;7Z#sr=3AGS z$SzY3A-9#^6$ z@Sm6JSfD?1S1u;+$yej>IXqldm3lKAk&%+`*r2{7E#EQ;qRF!XtCbmmboSu&n1YbP zOLb5a#E>}1#{{+7twYv)zEi zk>FB2!JkSD`lWB;;>@lJx_#R4g0Jpm1+%8Dp6p*gp3BE9vb?!7fT!*naF}1X+JIup zS-+L|VU)T#?$o%wyhroZp^ zcq|!eMqrK8JKGj|fc69GW9DfeG4hSkv3SC-?HXT~t|NQH$Vjrky)i^G7Jj6niyB!n z05%&=5!`IzhhYfaGP**ONcGA7-il{O3cUKEuuT`J@L;e=0^NonI(2W*ajsP!ZA}4Q z1UecPhWE@HUQrdhO^eDq2QxouipI5@QS)1}wjlB4Nq!erCbs+mR~OX(!V?;Z^$3-| zqS5eoZN%_z&!B@B+zLtR?VBL{OBUp^N`VSqXDL=YIr)!n+oDbcsSw=#f!vhl-Xe}p z>2cts!=ByhHVlY+6Z6C)ii#kO4z}lbI34J_xgR<3y_WS=H2W*b|>4O^g+a01uC{lX@Pd26~4e(^95F-W;Mp8?2L- zl1br0B<$|v<;3mRynTHsh+}a#xr;&u%^z78AJQOsJK@&6mJN1i5GtmA5fg4z7$o+> z3$tr9-hjx^z(P*Z6UoCtX7OuRgS%oee5HM6z1IvdM_L|uYZ1uxd$`b$G;z9ZWL%*Dq)<6p z`O5EwTJINfu~#R5ff}u_TmMaa(8>Zr1CDPg+bbd7RAY%V(`w0;cab&6MNbJP2V%Y} zPk3)Gy|6tT5tPA173%5EYWq&Y%Uzvzh`xvKbKPaT>vtHRy0q-UKZ??T=G*PJ?;)1D zmIkQ3bwkNd3kX=i4YUH$ozZnmhUcjOXvEI{(Kjgw1PziH3`-@#Z8jIBDX&@+uRT5n zgE}r#GW{(GbQbgAaw;hP5f5X*V2^_MG*ffc3*VkvoG zIn#z7+U<34`XDmkdCDD`n5OGNR0t}u2!fhHPQ3e1SKH*Ggqar}hEpM^)fYELKc&}> zdBubrB%Gc$I?LPcIV)|6yzP*jBur81?HKSlx}6M6o4{&^=E@{!q2H#OSGe=l=!25L zkqxc}PE_XVq+egWGzr8`Dh8d|Y*}f84(9R2$Gc(RV_e!7)Hr0z(lvD9Yb!H&41|8f zuJ${RYGeb(WamhD2zEz(!kQThL0usYo&YtmS;lL=*4X<9Wes6|VMHt42y>qGufb+y zvv;q7^7akeLC*}bX+S#CoWyu6+dsQaQmR0k32Se503DQ|SZ&}me|h4d8`T1{0KJ_C ztiVc#3AT}QZHPR{{@#fA%U)203$eN5{g=Dn;N1cium9!$vG-0fqeM-==VRNpZQHhO z+qP}nHuq!OwryiSnEih9O(vOSPR_|BGdI&$-PNgDE8TU`YgPS!{e{1WLQ$m;0go1` zOKN4RtAiZ_nUeEbPxO-ah?;8@8a9Cfro1inV%Qm2Pm9Liblmvr42+ejtMvY%S$k~P znHa$=*6s|9w?vcyF?!>)4(qXCXCE~knVkkQgi?brSU;U!=L2G6g6=<$hawtVQ#|+Z z$JLRV7ce!2om%9F^^SfWi$J(3U{^!KnI$p2r7lE`Z8tP6g;U9UfeF_I0auUAJE%@R zg@*xAJ;G*RJxsL+0~;rsq?v+Av))CejkNP>`0!h4Yu}AXt6A35jMcb3cw!i zYOEf#+kVp?Dk3OqfjCY%mI0S=R3VNGY`XdA#U0h!nB(Z_&wb%sMoqL_a&82jT@e>J zzL&Wo!^HrK0LFHDUDYbHuX)Y!ZadJ^NVuI}lneuo-|4^|tv;Vt4A9`pj$06tb_6``OqzjM^Sxh5Q|8sQ53?)hShQYg45Zzlph zG3AG7Y1HHNF0ibBu{!E?(hwXvTpvWF6g%-#MzsUo3=WvKUP!L(<>7Sw#`=t`?%0ji zXan8jz3x$Q^{prp+p8?i-yEz-tLy%Xpwb>F3^JAMJe>{QXh5Qe_yA~bK>dCBlt)z* zKITuCAl^;>9q`OI)&ywk?q4`L^nTW6#p5oH_p$UA)o*4}kMw(ANFn(Mmgr(d=%I}0 z-L#_Pk9?g|1&G|d7e7>H&KHZRz?yFEHTSX8iW;Ir7rrb>`Gi+{z>6?|tX<$(SvMIa zR-`Yr$g8=?_GMdw0T#Y`KrAozIydw*7f_q6@`lqq&rp&ERo3J-GkmN<*FJAl^I=h! zSuqj?lM>9d2J>7O;IL`A;Sh8*Rx-b1+w`5>jGwZKj(FRzaCSXzAbs5Xzla*MKdDt+ z{2cpZobP<2-r#6md#P;}OeT#`b9oF`SF_;!ptzUi&jE%(#F$I!9o1!yRI{EVv#v9` zz|2A*yjMKb--<6vfI6b4K~b~zRhV|fxbam(-4O9FJf*Ri6gUlK+4LxH^-~m8==8th zsx&1XILbxgkxaepT?7kH7qp9|I^vGoA^y_mHkjm3jNHr?9O3h@oQ(af{L?`t5F4D; zO=k5qzcbgqz+;~60S5Z<2TnEYJ@qt%Bb7b``JEZNr$WDU>v$oIG_Bty)*i+psSRFj zs(|xjPoR|+Eq^yll6hej8jhv5t{&Xpd)h0aF`dPk!3WToL#641$BzBFkko9&_WoWV z5ji$5?1aZVr_T_-LR$N$G;iR$uf2yDlN348X+6%Cc)$W}g>*VEowSfy-`p$DiU0m7 z(M0yIMy_{a^+hJ?T$&_a`|$E9^=HgbT--%#63)PtN4-tKb|<4tQ~eS8{*DurNdw zoGp&x9+{$|{%9K2n*oE^`3S;-dm9Hx=zF{yK#40aASV%StHQw_7iD2S+c3J zH{0bnZ<3VG(9Z0wZd0P`;=JRuR4i0DgoMeJItK&+umV<=nCsK& zbMQY)I{>plKEi$@W)vnZgVq(p(nwcH{?ZFQ00@}7`K({vEY$$;#VItT`S=T2O!IRp z$oIk*zX<4IO1=X39F~&m zI0^Ri@pkq0_JPp8PJ{r8+c%dF=Hba?@WM)0Fmx-j0|bwm0gHq!iZKca-=|5;!E!VP z44*7Daw~&6%W2nqA8&?lb6xPgzU#hEw?lXNGEItQpl9spyNwRe=toAS*Ld>~G~+7j z(X{K)LG~4&WD}4Z7w+Gng6htHOV?D>I_!H_D4vsb`8bCKX%*0{i>i;^@6C?58X zU9}=Vq@4Twnt8z#LKX!1$#CsJBj%0N0r4OLi6R;Rh?ydkYp}JO6=arQk5tFN6rP7L zkb#n-NX^OkM&c0$@nb`yY)B9^irXuIOLGIrvRIXb%BHC-$~L1MA@Mh0(Q^%$L2r!& z-r6@X+50Gh#E?x%ay!c`vo#8B+;~(-WzYQI^ZfU*oRwY=SpMs^;+*Gw3~B&hSAu=bdo3IPxSh=hPxCMA6d#i?-V z6<0A_$l2~UWDA7^J}p5*q-yhvm0<7m-KM1&TUSa3it4bAwmtZ@&VukKxUUx0L4ZY^ zWuP2GB2c;fEA#o>^eFllyQoOh<0J8H;4YH2vXtwc5w^RW7;-iZ3^X>Vjpu=^m8D!C zjIcfB*pPFvzrTTvNMdcxbn-;jNHZfIfA;mtm4tHtdaawe?;{cE+D3b3qu#^Z|A~ln zeZ4)qS?_)YIR2-0GKAIA<2^;U-e32~#U;2+@p8L3j3y zW)HC>v)$ET)--(~nQT{2lZ|H(bc8>_If&<~`k(TW4C?9Gh(2Q%;a#)H`PGmM9y4=# zcSL38)iQLMIjsy`W?m~pm+63* zS_;(|u@`moNZn{<_lF|T!49(d|CtFbkWdK_@y<~NeJI>kwy5BpH7KmK;J*?J0Mh_8 z{$N0!03sipuwTpwS;&MbhszcvoL1h=f(W=R0VF0^Vw|_wT@o9d3j1^{)P_=;i9EP(hnQ1c-2m=^!>`G=@F@m|o-{pYd_ zh%I1$XS{1?B%*l;AUE(_V+kV~4z~WD%n``8SRZ)=5oLEGa9q)g7UqgPiiol^891Tn zLkn|B9z#Ugl?t3x^sa@uERP|g>`nzvDth0-T#?5RQFf~WCl!5QVXnwyh$y>Vfs=|( z0>H$whdhelUqTo2^`3cMp^5&EK*zMGJQp@PVe-+7JSc-eXtH2k8P*t0_YX^kD4A~{ zr^asO5~Vx-gSk!Lvj(z3u280wAIg;SMbW*88ifoWSo`iP86R_kdjL}3D)xs$#?Ap^ zNz?=^$S0u=cxwqVzWMogs_B#>_C~+*(ov{%^M%3lO7{IN_v>^IPP}RGTkt%Is7p+g zZ%&}-e;)A@{tCnDHY+mN6ZS;E^w3eLbmRbG@a+dKTszvNG4u(!ax9ZiKN2Z198r}- zrXWmb*tfBVG{yk{A*Gl=zz!`dOlG7LZVdTJ10M0}@xKZ#er_=DZKr_VISkcIK)Y=f zx#F2rUqM`059A%3Jv`B1Uc(v6(j}4NVP;XAGmZ`XQvv z5uuMRr%2_XaT?f>2nc~8a~$2s#Y8{|44UKkRxTt0LSV=o#kX=X5fB1H<~Y8Vi-~{` z7&6E4EuW7EguswFj&0^*SjOP@!0g={W%|FUEG2G{{_AL>^rV`HHtGExB&8?S0<=lr zd;f{)x%1*`LWj&<)`ss61bXpzSG zJON`@c>a>%yam!GjXvZ;Bd~=7CFGrZ_y?0+;hOF!EF`?lHPca;Pk51QrlYWsU_P6| zJW+l8g|Ix-m^DdT5jvr>{Jca8F~khxoXM0PXXT>BXymDpL_(}feLk1yngp}c+v*Ne zvQya;FO(}fsKFL46ij~q=GmQ_lE>99S1>p@W`!7buMHoAsSqd^x?#P@8$(3PjEefH zV{FoBA)~%W>sz9w0nmCtL>|#Qvh`o(x9LSR_R;N60?~~BKWf|=eKz;3C-O}n&i2YU}kv#^Ms)mbXL(U1# z2NBrO_#M~ln%TPABd^Bu0A<;d(Gz@Aor)^GwrP_h+^Uyk(Pot&aSbxK{gwhW!ySh` z_blQMv4X{hAd~{koT7^*v#hYq3E z?Lqo0mS&ijbMzl*O3BE~ak6p$c17~r0t?MMI%Prd@U@nnR<38o%RK{tMFfDP4{X)W zXCJP}Qxe&YyWt}_Oz}ZQCJljcM_+U`^DfL@-YGhR5LjF7uvkOPPe5{{)sWa0O12Ph z5Wk-1|1K$~L&(`P>+BYCWx_U_)PK9*y#Q@76mo;IlH{K(?6q)cV;tT(O0#A7Vc(+m zRLXbVAklakV|;~MDktFgwbGcq8=QKt7d|s6>rGq6pV@3KUF1xr^Z>B(oqjHaXV8%$ z+dW;Zuw&5US_88^h_<2F@UiXF5v~X3keS)=Wg4(YX)be9%F;8clvIPSK6d*<+lQUo zyh43!6b5g|47n` zWWLXU);qo=1Z13tZUH$Nn3`8KjSeC;vGEKH+bCewQB=WH0Pg!cpzsfdxLY|sYPpG2 z%mVabEUcm1R0~aP;ryh+L1w!81f13n&ZFteb`!B*`eyvwQL=h7>r(x@xs-YpH|eo7 z*Rex@1a&B)$|4g1Fu+*XWW&Iy>^t&qgex+=%ItkYEs7x#80`c(_pcKKyCSK1iooa0 z=9Y?Xb?gP70lJy^AL&aATSrhghW%8H_`Zbv<0GG zrl3~ zfa|yg1#?XK1b|I27-Sh4>aL;g484mI!>^^NIxMHG2C%|`6O;?iLaCZ4^_($`SXSZ#liq7=w?N=&y zzTU1KMnEc}cg`>%+_(w?T(gKx>z4*>L$+Mclg5vQt`G8?-tJRSro>AjG}v&dJuoEY zY*%NQ{LV0?=Qb8E_G5u4z?T<3C>{R`X&qAJ_^=_6cC6JB%Do?QGo|u-`VQ{7+)}tM3!An7|)e@j8n92IuW2J(E znRnMFS(I;v+o z>xgEKKBP(R_x!%{M1smHuf?UdBEC5!#sPx&&`T)l;tp~ zbuze-A$iAxEA9E4rEikfyH_$BvZ2V&o-wi6+C7Yd-MawZBVwy=+_B7G1GM%=Fm5p5 zi*Zn(qx^22VB>w4SG_^(qmq}oTe1Acw+uE4u}-z((~CH~@W#^;{SY`)dn`_Lq&&9r z<>Le$sR?NLMXL4T6iclh3Mw$8KfK!sww(sLcs;m$y@Kmw=ks~fOF6E&Hd}ssgC)FE z<7fBF2Jj(3n-zzCJ*=v?6Tl8J+77jn_5rvcgI0k_<^7*?o{=GW(g##PUjfsZBZ}D@ zWQ)!PDuIQwCs=mFj7fyg>lVrKRrm?$arZ&E!17Y0LPK&3>DIT?&2=+lZ>&kjtw4^M zvm{F5@me9q6_gcldC{H$1@5xHQu3Bp?qICy;HRN)n;&yxiw! zThncdrnP9$v23-V-tVKg#BtdB=Jtf_6(FOMEYhMFK@EtPuq{!*ftqe&A-3pMQc6Jf;sYv{t3farmq5S}@Qftnwfm zgyEaP36L_P{bRvNz@rp~iKV8*ch-sSdK^VUCt5p>Fdd$Lr&3B|e$e>Zsd+XYGKvah zrwFrAj33Fg6Q8=-@KYp?*l(Ltgkdw0Wsmcryt47NnRF^_>2m(z{mX44EC-F$3D+S6 z+qNC5pRR3@vf4d{i8Xz>u$AWZ@l-QmqYCxLz>YLR2YuW(=ox-iB{?t8lDlA`ZrlP| znK_|eiN0m9{B07v%*dSX?^2SL5Eg+aB4mjaSK*`cXfTRP}>fvS%{;A z_wj+u=K|*@UDsj19@|~~0h_l|s>&yIzF#etg~H8*(fC1S4Iva(vV@PLC5etB3Y;)q ze=2$cpU?X#_1HIse>7>lOWsHu?Y0e5GQvO-S~``63dhDi1_yzhP)m)(K3Nxw`iZt* ztz*tdMf*EGgng<7l%WCi>K@)>25+BxSkOE@Uu><@e4d$UGGo=k=mNr8vNvG1TYI0Z z!kQX3wh!~elj?fjAc+A?)gOC&>Xn3T*STy6|Nce3%N{e=?nF8uv`K4I>YdOTd3gu=4JHcDu7VmPW8ulHOm**D^#{N+=L0m z$e*?wyLhyy?gn!D>LhY$FE(`v>)X|Gp%6{2cjS=~fF7}2<{G@!93!s$?jK*(9HzVq zc;(|xjU){NcYg0I{KeQ+7 zVY?fGfW{oWTgH{+v7M!f_7-Hq;U%kubW3gcjzs;I)ur+}yP6u@o&`y9l{z;EPM0iN zslbe}t%p=u=vj8Ux^&Bq3Rxrp%-Bep_cO0y4b|by$?STn7~>ksWpDT15_YCzjlZHY z+6e-tgjT3`EZ+lH0abs>y{PS)O3xL%>yPaaL88CT%G%6Z|EfRmI?bCAPntvGWzg)* zT9$F|HN6oZb}GIVnF5+&L=nH(R10qiYXi;7 zL|f;ZmN7&Qj3^Ddy}_Hp(iNUL_v`JMb?}Mpo(OLZk46V__h;Ae#Cu?Za?%`)V)2x@ zEwA%7>l{!00{P*UP(7Jl$El!JRPEllkcYS7J!iA>L$fkVwVk|IwGe>=G}xP(jMDGE zM=l5VdjTSTHHe^4KHLbST~bDla6Bsqg^?^aDST!jSG6_dZ)?fYuQ4UZ)X`X=1!_&x zjtid_qT&D<3r+_Uc{F+Hhfp7~f=XvtIVuIO{7HSf-Jp%X7g7=|wc*w9JFd@EMf&JY zZ0}088Nv_PxwMwe>eHWPh;gXb@o-~bU6Qc$a+@i*dm4}CtY74cQ#|hf`P|ZVTVBcR zem1=AEjia!7Pm`H{|%B=GnlgX=KogLXF8#|!aX(y<`*oQ38QV(tb|#Cb@)Y#f80Yl z;yA)2Z3g(S7x+plN{3^;(Xk6e(BGh;f493AhhnCb=JtMDfeZK3nCz}a&C|9Dh~%j= zQJ?61EY}@-qGQI!(WX@IlU1s%J0Lo6heA$T*;-xDa`WOFJazV`B75%qb-Jj;yZf4^?Vr{-mi741T9{lwWFtkUC2@di z!QDhaWQQ|ALpYoWaXfX<)dp*0Ad{wPY;ul@JOf6poZ;n z+%(ZXA0|{<1QR~46JX4=qK<7OpUqz~(Xq$=WJu^%Qg>VTUq5KIwxYXe&LV!X3q71P zN?)4Fsz}_QC7rOgB`rncBsFEi$RtQLf1Y|>#+~I;@;}I151-d!{qEeG-W$ejgjlp3 zW*Xo$PK5)KJIK9Cu3;pGX9_+@X#rGFXq?pG${ARJhB52GK&ae5zf13PE_t!^wOou2 zhxkIg8^f4XwhsB3)JZHQFJ-aH8L4R&23EYqFDX{h(ET2V2%t$f?ILMkqc04k$q0y- z|GwEUM*x+q60iq%{1jbh|569{d_dL}2FSRg^vnKv5bxX=u~2Ms)9&X6{Q?%tn3tHw zFzy-khfp5>>H(QEA$l`~c5*Cc|9nRX$$YJ~$E|B%9BkYtKbd0LIfd@CcM#hhAgJTw z<7|l|=I7+&_{+vt#PlTtdAzqmoiq(dA!a43=W`EuXvb?#g3io`AS`7M&}kRDI}=i% zQ+T5)M4+r1n2b>JF$w`ByiI9@=taG#=Fd%V;ugLPyMU@+g>T%tJXkyiEVo-TObW0= zEWp}SHYH}g>wI*r9EqC4o>LrpHOv5FfgywYe9mX+3XYeAtBkij1@{SHJ0WRy%k?hE z%-xb-0hQ_e0?;ZnM3Fl-!Kqk}g9jg7MV)UL8Kgq)#>MJos%dfxtFP;YT3bW~O1qMj zmrE|b5-^aN=x{?PGbd zH5=mLmF6_)MY$}}^9qvx_jjjfF1WD!0qd4POdO;i zatf)?fuA}Xsf39%r`gW}pp_1lLd-Bd>(28HwFqc~6?zMzg)ixkiG{jQT_*P=VfnCd zx(B64nk4p62Q2&~MQN(+Nw`{~SrtchG(9IHQTzZLuq6RqAE&!jFOE|%vtM;-d&HQa z(;(ISA-Of6+bcK|8abl&NWu2X{gH5H=hxq%&glJmoabK-Qu5Zdgfmm>Ch*>-Cj9}& zc){6ZSjM<87>^^pTYZCOR08-oK)(*YWRnp!z*@F;7}ldSDpnA_ zXm$sFKkVK^DF9Qbv_V$8@PIC@S&jnS?9nmp*d!0HDaYT|JqBKHM+TuEEUAcrYnC$y zmYchP)f#u*@%wTUiZP+4qMN#p3Ff17I?Wa-w<G<{S@AOWx2DX3O?c^p8 zQ73LRU4iBP$b4mowY6pqO0Vck9Ke(Zwuw>TJ8U+7MeT3({AvL(9N#d>Ewbek#K{{C z^;a3LsqmAGP41sN;cSpd2Dht!S_sj<$?IBs5zXP92B)YTjU8vwo;RnXY&fC8Klzit z!?8T63iShq_7gr7kTG=4NWARY0I?l$^&cMW)8hZtEfciks0bPiK9|b137IghNFl$< z$F>+gEm8>0+HI*48fU-_%f~!MondW!F_h=y@R!}2`6{Bd$i@1*;$Qn@x0xg-6p-FE z+!BKP5deEkpj=hUawaN5m&QWvoQy$X7;^xeRD_}n#}l#JPUVjdDxzJOhOJ@ zePPB4x>xUGPSkd*SKn{$x5}9l^q1*C!={>LHvcl3if45Y$QYb-XR6aVU1T<=m!~jn za*w)yB0T(Uw;V?dE=l1eR|vhm%uLC6LAi1#v{XMCEM!&+CRz9OcUvA}t6<3ovZ##Z zUDG>kXz56;PM`&2-}8~ysA>c{ftS^_lEAEQWF%=J^cK5biS2Pvq4LaosOo}YOzaWgI#Z^3LGv`;zT ziwy-WD)$Bm!!6nc^^FjxO0ne8l4Rhev&+?Gsr)@I6$sL7LovnOZs(_&D-yB;e)lFx z6(L=pLihMa9mLW)td}P$jaJ%YE*XI?i zuR0ab4FJ^b;#m65UhEboTN~+V-1FNU(j*Jrz^ghWr}2zRMWZY8L(@1hDg2an)0b4Z^=eJ8qTJmYh+gB!0~eVx}Vc28f88g65vyVEhy)nw?+UnR6> z+?p3{8DaQD&~LV_QM|{C)#)m0iVj87LZ#Ol_@&p@rL;Pb7A>*!^(H(KPn1odR3VwD z5dCFEJ6hp|dNo6WK!5jwFLQAXNi$0tO?@c%;SMxVK7f2uKBqaG-g}|N$@9T?Eja!M zyttkx?dhA@_>nvxLtW;Foe^+sqO^1cPIxl-&O{55HNo}RbOuLN@P&~JPq8e+t<-uT zYxorIVr-f@fCYX^=&*$z{CfP_WR9|0)6w|>^Z;>Z?TBk}kzG|9Wr7WWWm_XMC|nE_ z8VDQchs@#Uk?^fHvF*}>Ju{15rKj8PM z(Yu)xDqy2DWf37AZIA@Hcw=}5zsU*a-yLBG<*${M_)+XW z9DfmZ9qhu!?E4{y7&N!FlYx?TYaT$3ygGnq&LoQ4TbC7#3tji{n(~Q&0{as}aQsV) zj6Wv{WYS_+)c25UeTy8CSBc)wsR@K-59nebhTbxcWYBZPi159I!FB37b#aCKIrc(a z!NCqJ{v4HZ(Tv%p8C|l#V9kDh~f3e-!om5MhC8tSPAySty(+QuT-`5md>H zI}4})bN0&^c7FX3Ndx8yr6ebOO#1bclyhDO97Z1KJ5_mM2v64)=&;`PFCMIt(`B&c zLMd^UBo40Jy}Ph;B%)LVe|JZ0KYp7eXx%=f9N_-tc#@s!$4IcBDvNFb>Ru%BwCx>u zu>09lMfJGS`AP&6o-ZdpxVUL@7hCV%Z}zbE6wyp;Wj(wOI?dJ6?l9nTQJ5t-#Ar5L z<_QdekT^dn6mLmBO?@k5s{b9DB*b+bODj8)8A8ysdWu~(BU*Z=4I`4!QDi|j5b$9A zloUs%H#WihOFmZ5(^~#@#`2`Cc%Upj)`$K}w`h`xMZb#;vlntXe4ePx2bP^RPeNji zFAp9BSlAx1To6};n9R-#01DgPUK5>y~yK$@A~&nlrw zf&ON>X!+m^2<-4UHNHDr*4rvtnK2N846VRB=tk!vyM4eFU};Tq2hx!SF~?R*i*M$ zD&W!;l)fhti+~>|j7{?`2MwmZ5#7@4={qx$so_QbrW$e}kt`p&0ZWs6OWJpR+}xOX zv(SbdXkRE8z@e#@ggRbLis>ERiNY3}^LOnPRfy5wFCu#KGJrC&=XP z&H7<(@sCTAwoGhzIj8b&g33xk=_jleys8WdecexaP4NRto3Z$mP8t z28-+#TD+j)7aM^g3`rs#F!B2w7;B2B-cg_`#=Obzv_IS15kzMlZSeJ+D>TU z7{G(UfJtJ4Rv_2zhvAyW`qZ)D_<*Bi$-KscM!3aO6vnw4cy zABba4&u&VwS2N+|it#>ci zN7olSsDvS~0z+7TiV<CVD+~4%n_<;c0HMR?^eYD z*g>YPIRRQOfD>Z)OQ`B6_s6xiti@YXYN=;wx+Fp4xVZip%IWUW+^92W;FCp!+Q3C1TQTDq0*n;SjUFpJTu43qOjDd6*ZlM`p!?an?o3% zFh#93)*j3e?~&(q;K=^U%N_;<=-|Q2l|n_yd0}A^Y6|2d_So7^g4=u zlfBvQJXVG11UW|sVO#RV9Z}`mcJ9{Ub&WTTSckEFX@jKMPC{ zC3xOul7Ih&Ddvz4Lm1+OZIg0a;ra3n*TomA%N+w+OMyqP$t&~lrU&9Y{!2s$8_w}J zuE2uxdL!BRke_ASm+}e1q^xDK3^fu@?koN_lJjXdh8hSR>|SCS97)IC9LVAh3jx zG%6**LPCGCv@xYpCNKPIR%L^Cw%8n!u~Ng)FWTJt>elxZ*SX5;B2$|BdEL2aZLRDl zC--Y?BL<090F0tusNS|y*h06CR?!!69DI^Zf_2hX_AFr9{Cj1Bh_a4_vYzkpq>#F- zv)H^E%nF6XeN!K!v6%)c0Gcam2f2sqK|(I7@*)Q8nA$)Qm#5u)hW@4$w363(BpHJi zRu458_alcHMEI@dL_@M9eFeI0KNY%_bGj`z9=8@c*E)bHR^TA9K2+t2h%i! zM)r6{$b+)R`N2PzY_TU5JvHDH`IAl*Llx>3U7Ks&UaQsp?a7~ha5$&G3|r&`h4GE} zl}_mt4D4N*&o|h%6||~S=!E_W3LjBmv~h^WVGE+7d;NnvN$ptN=O4g#k+-_`+a9F| z#`aMrwYm(Q6a%8;{+<0YjFywf%;E=>H{2mLWXGANbQ)W%#B29ubPwpiklRt@$7A*!xmmGz2e(9eN zDn;W-j^bnB&Fh@=leBwjtECOwlli%HR12Q-t}L3S?p zw7-Oq<82ELAj zJ|a)6YAei*J1f66pX@I)r}xBoE53R9!7_$oRW24lv$(dMdj6LE=vcpWCzn4r z9AwpL9M?%7H{6Z56N(`=lp=g7Sp zeAp+s3{?R$z#!$QLKKs`*TMOrUfb3v*>7;r2$my zYQ_u%Uc9*ZR=SJiIKn~dpHRwG;*T1$*^cakqVBLrSyeTVTdG6_e?46@3e$bl0s=*W zt%S6~4S8AYHUB}qw5IgQyC;>)cD*fT-dkG#PqJ>*7Q5m+p{I01#CBZv=ec|00S|?L zTQ*36;7*nv&?k`n0T;z8$ylHao@qhx%M0$Xo+%XJmqX4YE9TE-gefuO%n`zUcaR2y zIWK}zSaOl1_9@hwar(f;4e420vb&&=&bp|?58RbazoP@}cwrjcH-v%Ma>6GQB7Vkk zZ@^CwPx|IH9FFEs-zbz~Iz;^+_A9V`SaVbL!aNgJ7I{`F%tXxJc{t{J!EB;O9yVH| zzuv;Zmpt{nav3krSMd*`R8er^;_Q=cQ7w7jOLVNt?b8kk=0;Os+M$W?nT?D{ zm7Hr>;Vja?jjn8&Xsz|hmLWfaPw?)cAg$EJxV_Fth1|7mFT#!uoLXZBVs*}(@xg~E z+q5E$SU#T@6#=?7=3|E6)Fmey7V7>w?8(Ommz8hzF3E(tyH_VkqYHSrx$U(oj1Q2D zdr;i zmi|8cArqGd?ya$jYw?G3*dpM|+B?ezRuAm+r}ARd`lmgklv`M}uh#9ev<@t|zC05f zLYmKw=_(_?bNs8b(Q0r6%gNha*?PMiigqut_31}(FKqvCb2q6QlsFD(rXDL#?%4?}`1J;-qW{!=zHjtp?(~Kq3>Wq6TJjUmE5l-Ue3L#5pp;3k zm37JR(wi|IV2%@zIT$QOu7vfXX-Qt^o9Wpk$LK!jR5LQ`Db}EbmFi8Nr36h|VSqR{ zei)Y`Vop&M1Ty157s3F@O?sBX;QZNv0q9<;MdRL!TY3 z;%1li?y#PbQ-1ZcFudKE6*;K88AT$pc+_Z0(^RFti{O3c0M_3;PVRr_zX%ORlW#B-N+1V*yeS-e7qjo zTQ#U7hXyCD@ZtYVsHYxEVIws=G)O|HQ6qY}9Py5oS*?`qeb`;)NkHg2EJX=YZe{`6 z>DR2+Ei(`8^ljGTky(It@;T%6z$`#J^^)~+XcnNIe#Lq3kcp2TbLH5RJ=$y?qIGet>c~l1sv5Ag@((x2GcyH=4(Zql&93+uG7Up3J>d zNFP8|q^T<-_YAc}g!sEIG89SZ{|^&NQ4vsF%bXZ+NYLd6~il?s>f3c8}N z?sUYiC@uzEXLtdG5OChVjr1D){2H{d`oRk}|G}FeYv=+M8;p^UnZu9?^`--;ynjfU z!l?g@8#!CgO#l=c$iccL?nEruJZ4%!J5P4GF&b;TWf_wPIjnLqpAP8j2|qSPE=yms z>LJY_KW-vaUiMjfZj{HVqe|plJv$DhgU|e^QMX=#{+T1HMD)yN7%W8eyt8~}lGVuX2e?C2TNtG^=t6Y+oU0Cu+dLxOQz$*?W+^aO%nVSRRSjM6pMd}|AS3du z;XrYY`SS=ML=5yNm?%D?TftjogFP&_PW=@@d5f%Bde@Ot2riXq(aa zPM6*2j(pH7+HdDRwccmB1#!6Gw&ZB$HkrANxgZ@}+aq>R!qym-v;`UH7d$p0?NwUI+xNSXY`@2?RV)f!D z;lMYm0z13EDlATPCHr?0(}rf|B)z-|el*9%IX;PknH~td@}+k!e!nX(x9=D_P~NgM z-uf!@;~LoxgeXn={$Cz|$)ElN1PVFd$0qjO;B8=kiIXT-dPEfIsuIt)i#Y?q{GfX^ z;ehWmgXvdJ`D6fvtM(UXRp5BBw6QWS z3V_taqTNn_Myi)q`%?rgT)0hrJDIonS5di4onnL&#CzbDZnJ#r{y5h1Ce_LNR(b_D3H^SEd*_5g~=7i%I@R_IA5Wd>tEI)3JQLk zQhqzfsLUhODWjorQYVRl1STCif&OXz9MYA=Jt=MpL3`^Zs%UTc|@_##0yXOG#Jx8MkRs7r2Y zUfsG+m*HeB%2&`)Bdu7JvbINCLXmoRI+Ti?ZP3yl9=M$=c9Z1kCihV)zz)*;Xq2Q0 z_Ddpl-W!kc-VM}7Qa17=k8e-|rDw9vgO7YVn2~Eaw>gO)LjaiwwLo7j!3MBWOrYYBnk4f*CpU9npDr!NNXK@r^ z9M(yu*5HckZUz9nhrGmeSKe1n=V~Xq^2G3!HJ{)Z?&9S=CuBbpuj@^)o~@=zaj{8o zQ_kPSRdcfT^!9ACw+>@ZEX6DD@ZE8t1@yQ33I|7+x?POI*0H;|(c7mR&VV#@Pmc#X zi!1I`9>>Gb7PrgsBEu~cwU;U#S1cpl3=g5~-IcIN!1(3Jgj~${_*VrH$^Dqbvx@}f zuS2NiJtLg>*TqKt#8#^EH)ybLM#m+=&zMaf7vaWD!2 z@1>!*gG!m9cZYP!Lcz32Y;Y)Pgr*)~OJh`+Nb9&b6#T#AVNrYtPA#NWf8{H-72~_G z3Vw&_K8*YC=p9G z^o<#b;l@=M@z%IoabT-^pAc=g_AT=p`JRP>T_e3qxSXt;iRwC_!O&m^L~-lKd>9RI z9^P)4cN~-T>#4{LHd-s@%Ho@5Mr$Nyry}Y-L-NhzzuD-TDrIMMLcDFOaHV1^`||__ zf?b>Hl>TzK&q;CQ&W{CcbGI?@XE z!0IDo`<`*rVPs71{FzAyvi^A9<)cEiqU-52oAFJn7Ki}GiyY08*wGeO8oy&uV*&+H<*I!&ab6BJ^p(& z6>t8kF4a%sVFNXm9j56a?r|8QzZr{AR*53E71@&}d7Y_s76a>7#AnBP1e)57^&RQGjNol%dzHRIGF|l^4}sZ2!HT0juYXE` z3R#(x?O*kH<}$GN=NG&W@CP<4Jvj`!ik`@%jpz1qml<#_o6NpKEwT24LuG#AZ=J6K zW7=o#ivt#FME0vrl~J5*PnF3F*)mHobfNHROS&nYhz3MyDMg{dJfMnAbEr(AUCBByl4@6J9%Q2GCsq3^XgugY?j*A>*hT~x?4cx%*IrC)uNt9o;i z^=@@(KPKYS?~(}R^m{?vD^2!p1FV;%4Zqr6;jxi+l$seoWvy~F)x`hfW#`+V1L!tL z@MBY>#0*BCg9&JJikZQ1$hodDZQN8O@!ZbVYxO78<>$KoXyf>bn_l6rFL zb4vIbv2r{&k%ZG9b_g$@REhB&HXw%uU?)hjBW)5Gc`YrrGdS3P%0Uop;CJKVNLu@f zED`oc>!nR&2F0x-7e%}7^%z-ij>e~IQH2=BoKZ4pLXnm=t$n<)7E5F=m&9D zg(_Q{qNbM2ITY0F6RMkhTkxTw^MDxTO%(Jr*Wu-nq%*q3;BU&-C8=n_Vmdvr2nHs) zp=vGkwCAouQ1fxzQxfeLz^sw+jFaDeLEdcm`8HH zO<#*~9d@?1Z~R^zk1)B(_i<$jzC(n|xB_wP_=>O_(fbGp;3DPx7S|32r$Z6r+3I@p&( zw9|62*1kBUA?<3w1`RMv)fw77dpX=drEsY_?X^i-JUF5wn82ybuj3N3LGCcbDZ~Fo z)+rK+UqH6-0Orf&FIvxc?Wt|>>30jUU!rA?R|3;BXhR<5xq8#nv6XbfFkgXPi53+7kX_iCfq+D$#+qS~T2tmKX8 zT^~A%0?~)Y=(pq)5wDX26V0dt%No=gCeHQ5U4o%tE{D0-C;aRLf@BzE`*OyfEAFYb zv8p^xjEw{}ENFwo5#uhU2+LnJ88qo+Wfa4zi09TWs@H@A&*KH987mE z%Whedzmvbm&n;c+6s6;0k|Qu(geu?_xZ0BFbAz+SG?Z)MK$B1mTi+igciGAs>BVx5;pKrm(|?a;(*U**mb}}8&B#sp0q$+v zv^5G;q(a?&RWo%&#dosLIa}NVWMlQDPujp&1xc1r-xj4o(gpKT z2wvx)LOw$OMfAQ`7kxdO!mksAM(b)jk6B3H)gnDyTbaP99i^0t*%e#<29l?<g|bV6WFO3GFPU;)qtGiS;hXXMaWfB*mh00000000000000; z+8gM-|3PoefZ6UA<_hcELBKt_0`%*q#l07~$`jx>>Tm|KcngC`%2der10;sHpTZoK z*g2-%t)HXn)R19?n)!>^qViKliOC@!n(qb+&CQ<4Kd~<1BaQ2NxPIfgnwq|e6vNCO zgWucfVnEsHt`o7nUkpUbUMJ;=(!NhLQ@o?0+*q?ZOQ?+XvOxP&4v-tb=40*&pd>PX z=9xdAo-=x+Vu=`C)`cF`Vdd2`v0asyU!Klq83yX&P}^E0ihid~T3(j6iXP0QLMa3C zLrRKRWD&hW>i&+l{Xmt;9Bzg5LA>pF1uvEW3Q<1!?)=Lt%h;$3| z7OT?NgXTl*ZkXLMx?^k&WqPFZ zaEk-*c(6V2{OXz{n<~ENF2rJ$i$jE0!--VT<|qAosk|g1rMCpNVD(Bdl{ZZXFK7qL zk@*Qz+hyZm=J5B8NgnH=wz5Z5`xzAxxgf-{K8>yHE~^Mv@!t0S<2r#JI)qdIb2B6j z`ao!8CIhz;i7l&iOt^m4z)R;#f7(e$srq6>)zu|wX(bCC3U8M}crY|CK73@6OrYz= z{WCQ|R_tJqJMa)&X=27c$nqN6ll67V0pOvS9$B*ww}=w5H42uVzSAJ-Z$ETKgea<( zbvzD{Okg@ej}|lmCQ_8ItSWkVLamdYjnniUSy8)3HqxVr{DPEq5058klvXeN@B`nr zwfm*{GmC9n<9FbMjG=ZcaMXI{>PVHf8+6z-O#(vXT;j7nl=~tXDS)$u5Rm_ABdYHf zT0*e5bE-=x;AyvA`l{zC)Og?G9$$${xgeI6dP<@T2929u!^UILcR7$3ib^t-<8xGG z=4xvhHcYqqxZsshb!NF0`+OR3vYAhX8Cmh7~iDIFf4+xy&uPUC|C9P zkowuXP?bu^bOMm1f}CN8yA107@#2at(O|_2AH^@Zrv3fKFc+L!^Qx)=NJKhE`6DB@ zD-7fV{`dt#Oe3uo@1E$lRh?p61HX`2?7j=!{TLEgv&*4VCcqm@YlJ(Pv((_;IvJXa z0Kiz|RsfCC4>EB)LwLOh9`5hsw!k6n^OS9NPL3ZXLbp^@=!wd{d*||FFbvm@X4o))aZjmL%677p)0m9uU&Ho^9T0BLNC?F4Ac>JXCPU zWXG!USLJ380V<1f=^Nm0kWD*Yb!I_*TRnDo468D+K!Up7iF0YND86%%hBW+@Trwg) zcO_Inf?+}$1}IiNs_84+*sRQDC14Ku=E5pRESqdjTwzv}p23#$bue zzhX)vO6Q)mU?s!?ADbH9HB)T=9g$}bpqvb`nACJ;jL?`^6$lgm18|bd-4?31;6ydb zx(YC2=kwDWd}Jl$d9HY^Bk#_*_I4mOSdJru-78Yfn-;ZCktl##zxTucP`{6Vkl7d< zylS0z)ke=^Dbkqxq8Khjz=sBA3ukV^DW1C8#l8n5zh42BCR0WAKa)bMKa+IyEkPiP z2avjBe@sMFXQ5`kF(O3xPojNnR~Zbz5H+XqGJ!M>&f6*57ad;Q5c{KX-`bJx@i#2f zKkJmk)JKsfM6WXDr%rr@5g&OKura)R-2@xm{!9X$GV}r?To?wk?r1QfDfAm?F(e0U zkh|tSfBVX{ZCqf2GNrhE<*VB9o1eWPHiSVJIx!8U!2Pgzv1z)nEcCl!lVj(UA_%~; z3)dM0O9)!|WOFa+%Y8tJ_o`?{NPfJm~O&DFGia zA3ema*wIoG#$;NLy{}jXU)Zh9R_6mUHpUBd7ctq=E+;uwCu5@(gLXU{6J)9-;K5{N+Yb@oN(eXv@5 z2@B4w0)J=JX=9{qJfN=ZhINz9j1gF-l7+HIQ02TCK0nx64b9jk2~DgI0mQjuX-T?A z{^Z}%E;L)ZyCOy;kNN&00_@04 z5ND9@|Bn?@(TlTMxmJ|Oy$?C{7Y|HRMt*{0uJ$xanLFoWL5xa_JL>_Wh>vuix2H;# zy6YTc|AezqhuM}>%-;*4C(bp0ejaiB$H0T6b>uMwmkdbPX6yUhFW`wfOO_izRP%(& z*#SXr4HON+4y7cWXu5nK%D(HYuZu-&M)r@0O<=^b>`mw&?;e7Ap?S0ZJFaxlV50oV4&87vOQykqDg>zPAsDYkApN^K6Iyxq7v404g0 zlPcWhrvO#^js0>Ezzlj?Y{}&-w-~@}jewg`Pn-mEqc&FPw@MCdQ`xT}aLBV!I)4&& z+P=H@m3c$qEIEJ^5l*Z4C|v8(bqInaL)Qv<{!A)ak=Oejojm!mhI?XDB*x6|i{~hd zvD8Cc&?X7IMu3D?Q=j$}0ksCQ3tAgiZu~+8D>f+F)%Isd<^M23WL_75wuV2%;uWTU`CEkY>Vk#X**Y zBqacwrdPHbNXjy~%NkV=i}w0GzMp_J6jX3%>BwPIifr-9t2GEYk~_hqlior!c+CrC zf==$YT!sCQ^QZQC7OHmpG@~g(CkhYooHviU*2-|r8vr_q;TS5V|bW4 zu?SC1xoafFhRWkG??*Qhnu=94_m}GLCH;OWsyJmramUL5tlynONB`w3_QTZ1vb8-O*{W_we;!9+wPJeJrd0art%? zjH8Hb{v550(t5$H$9SD0*lklH{TRuC;D8eytZ+|=^Lh53g7FPCsdeOw&P?*?%dc)| z-~w?NxYXod0}QY^OS!|(tifN<h+^WKQAlRWPmPZAM z`L9Si#ao^yYQ3AV=4CjGcVG`+SGM`+Hx|Gmn3elzn>E;I5 zLly_<2_i7}0s9A2bu81@i~^@lRGaaN8>1H+ghlZ?7h>bW5O|Xlsp=m>aV|_gx)*H7 z?fwyj$0h3J34ruQ`y`ZK*;nW`^KM0$y|LbGelTCG7~yI_j>N8p=n+r0s;MB}YI6lh z3Q`P)jNk=}=_#yn5|W1?;TnFHvuu5$=ItDOPLOK-K}-z##FYVr>G>pykuv$*yJ`7? z<*rcCD6ZY$s6Hn67;u$8MU?RVcFWP!5H!k2+IIAZXg)jLEw9M{$e+VzMg8C4%xrEI z&{Q89lJ*6=4-V9e+#v`?rFoK0`T+jg!mNW0-i0ZC(Cg1afkuct;LR9}GHA^8kKxX3 zL^1zqb`n&OZteDEe`{(z>fz5CxUQ6{UD;MxAGT%zO=Fl3=zzw}w;2(hZOb%9D<@?X zv_zq`OT)o>>OyW?ILIYz{Aud#L&^_Z0f@qgq*0ml%5ERiC;1H6(7c8s0!<#YMOFm$RXGrA}@WBMEB{*%OQ<{l2ju|M7hpt4*g>>IYm zR`uZ@q7x2DnAgHGHN1a^1&JLp09QqOfOvn>TVpS?Sj0D+r;Xk4bY*cZwcnKkQ*ZFm zkUCn5Og>i4$rNi5{(|$(;P(~`u71~A5F>~yADo1>VBpQtArfsK{;W+nEXUboQ7(Qs z&KB+AzQt8SzX5fSJ`GrD9tOiZ#@mntWqV# z&kzl`c7n27uB~gOHb&_NG#NKMVy(fbz1M~SZbe@S#^ zRAC1rY-_P!Gf87Vr*xHJM}_#=WyJpui+1DRkC;#LSHt>o{=nJ{hkmy;kznd=DpH)Y_LM35F#+XzD+)GD9kSJ3{Uo&=_B6 zen&yw6W^hI+F2l--S3C$MrsQ_4p&jWFnb0Eg90J|W_No{J>8@x@zx{ll0*FZI*{Wg2$ENo%)Z`mW9LpM>ld&xSdP1nFFTm@rh`4KOxEnj^D~UUWJ+ z1`iol663wFFiV=L(onn@gGkz04pU#86{GXmF;ZD8*bn$NGpBNeJ^Kk3KJJIU<>Cnt zjojAL0<}LXk_!83I4pr^MuR!>K(m2Y29<-uFB9llI8S5wu@^&)GeQ>~Cxja7CNQYN zw}mH9OF!f@$7w2TzAS;kK_L9JpdTld7t(|tl(-2+Y$X4QP`OAU=N+4Yi*kBLql?KM zW9;N@gsfIwmzCkCLZ%K>&0z4@TxeGicibwUKP+ ze@nnc0t@nJ8&G~PPNc}k^$s>>v}iGviyJnI$|FV8MUJ{C4F{i%$?#aKPmJAq8pFzf zZe6BQflUDATnv|EROc3^&48Fz@7vMq(OW$+@hB1V-=;3@Z!`gaI2UyAq?fj%%5toy zt#eo&4Z%QVtOfvXiG0-pd_xAbuvzvWxX4qY|C4+l*v|V{&xfsM@jtpA(nrZSV*_we z%(vkqW2U=8N!WiAwT2L3+sw!?>wtEWLrGgn8|X1Nv$ho`mYum=JE$A{@>?8VV$;t|bRq?KjJ==#=^RE?1VTfnD=HX@r*>bIZt5+8- z4J{cKO>AmP?D9=3x7+oT6|75c^{DUtC3Q$=?LPeaxUTG7Ipjcu!`$+Vc0CV9b& z-Dq0I33@SoeF|yUT;F1<4spXhB;(B@;>r`Z*M3qp2J8ygYwDtLJT02<6yWpwauru% zXt+mFf}zG4oMi<*mHdQ?)OA3VDr#R#6@OS#bm-mv`2^HBZx6Uvix+T}FzTJnFfP>0 zp!75DJ)+9`r?c>lhn1Z_cd5SnnVf9-fTNlp>CJg0v&Mz0IZmyT@h>(s1ch3%)OXU4 zdi+R6U}cj9%D^eY0kG0LlR-nUID{2U6wvMq$TnsgX~+z=#O=<}w-ZZ2B@lxeX65-1 z_p1YOqv#4@I6_W_`@;xAojZZUF*LHOB3LDNZNs(uriVxR&T0D4cZKIG0YJCv3q@?o zqlWw_@^+^Vz8C5+BimfHx*&jptIjVWDIWzd2_&c34T>U5YV`?V-zl*i;sS2E!jx&M z2?gLuQ+WBpt9@Gv2fK~BMz`X`+6)jS<8#=XmI8_?!?TQutR1qzGQ=K>%%9DvQ&-xG zU(NbF3dI~5g?0|amb94jYje9;WTe79GdMAe!_BF*Z@tr`LN#_`k3N+OLSe7vp9bDTE3aQxx?A8=M1B;DL3uz9zUkLqK*X8$ zHma8*RsmEwOg-`BT6K#iAGE+U!3!ZP^=Iu1NX%r@&E^1;zoW{?Bc_h-{S_-AJ|4qd z?*Lr&k@K1{uxhIC$1HyhWfz~&4SxUYi>aG6rkO<)q&OUbjaJ;C>0nZwK#f3Ucq^u5 z85{R?XDdmLjV>qOh_WdsPkb+PtT~^!Y&v_gSnN;hX(8W8%YAaBUZkN`$n2WH5DsLw z+X3s7l1HstyVOE~XN(u7OjiR6Oy@%ePO7-g#tq!~%7%d*vidCCYArO4DUi?=u^K%) zRC8zPpgUKlJ==C7U@Su;Q>X?oeUO zffds7;x<)%wvnx+pC_RK^d(ju5646fMG8(6HOs|d z2>VeQ^3kcVWc!y(cY*dgIN9yE9~DMMD*tg45GbHm4f17XO@Tw*nC$R)CaODW)|bUN2w zmk$_#)8dKn{!|xu^_^aWZBxUSInv`@18~I<=KlPw8ZO}!MHhmdIO{bcFBE{@vg~6i z_D|P|{hXLm&=90>K)DnpXQ(p{W6_$)gwwOQ!=p$1kn2oBY+v>R$SIHo`AXy-EYa8Z z@L^tAiO-thJk*kEr`N^!rst=nvhC8Tw5|?l00n2I7J`Q&Qzjz{#Qs4bsz_B>2=Z=W z&iap_=iW60jtk^)Oi_!x_xXK4?NhOJ>V`xt6OWc7l1}9xKSo9V8+f9$pl7cRmEyk~ z5?h&;y9HX`K;cr(?nSRZ6^aQ7u`wLLV zubgGo9fsPb@GZFQ3&L=ai O3SfOorh^m=@TNk>1~j7~`|J6-f#wc?gaPwc}M5=S} zD2S2#MKSKJ@3bEZrcgV%g#I0zdg&x3?LAnSUT-f9us$7<%U>AWb}jpfO|}mnUR<{) z#UR+jE*W6h#~=%8sU-jRG_F4OjTqI|-t~mad&%REj$E1VC2&G%f0@(_W$7O|v` zhH@dvwM&*>!JUr7zx+#@?6dIbuFOMp+ZU&el8fP2uP`EOOt%pH;f|+RpAq3rc~&VT z27vq>#k~1{>q$fW9adwwY5vdcRr%kkW*=^?bhJR(-MY;ZtqD45&$!bhp5CTn3ssLx1~`MvEJ=VCT@V$P=IFjd^I)*fM>~rMtlU9UN@-+z*PQ zBNczRiHH(nE^Lf45r0zTIR4k8-jq#SPTH&68WkG_97MCG-?QfL+06yp8JZ8_x$y?>Nd@Cn>e42f7Vs#cu?;4Qpse% zhwExQ{;;6S+OWbG&UJZTr5@%-mkh( zT?vElVBotzCokz_p^(qI8B*IU|0W5>?S=s>T_rt;aCeT{sL=eIuaak^Af8>pnl)8P zk2oLY!FVcZ^V$>IJ*C--`<0XG&~)2c*pmk0yj`-Gc)$_0qkUcn4C1!UO$h4-Tb zAf$zC&b zxU`CI)af)=mS9w=a7E$X@Fq`&`G7LbP*T^FChyLEq)^f8E^DBUYySUI7=|)X!D}JN ztTa=M_#j8>^61o;ooH6Itt7-G?k@dK-Fb5IPgd{lj5?`G;LAnz_Sg0>uYoHz0DQl) z{+CaT_bHQj0}RPRc1h;_WEQOqyU<%_T@g`KMz5m>*P3WfSk-J>Fw{B<+AKY-%)uim z13#cJ-TJ;49NQb_F-#9YC7=uOZ42F=yl479!r?}#s~_d3eG;2&1WRb-o)2zhU3J~P zxOxl-BH-Wb_W~BX+Zv%>{ajfV2aJFEdNT0)-Ewa>wT|x)#=&Tr zfalmVs4UM{>Bujz4Gk;<$aF(#_Qm(AMz)jtL#Rwg%C96e+zm?0#s1I5$!`_I|k{hJGp zK&n=lx)-wCZs?Sa{_HN6!7zNky{x_sn}?bd@_=-!Cr@$BzGN}l(zycOzLiAQw2X|# z7cYrbqj&LtcDp=951juf@p=C0!65zSGZB|AizZjhhSi^GSHj#;vi=dR-H(f^-1H$|Zsi5N1!>>UtT-U?2zBYi6CKK>LgRzY8aC zrnvYvd51KaNrzKKm$^T7Pt~mivB7zvHHnw--`+C1aDc+QUWN|)Smc*IRmo)J5y;r` z`8b;?Qyt-Y!exdbi&)}*$7p}-;%?1ivSlZbnJ}wtNl3WuXgRD0Vz~9)pZ_8-lhNI zSX}b*V0wF3yD)5etkE;?{0Ca)e+LXy?3z>4;Z*;z_`0SS#S31!{7IT-|H!`y@Lmlq zd;*^MC+5jMPS0w{q0^B*-HYiaXf<06g18iHE7#LAB%Z0eFdpa?HqkL}e43aO!rgnw z5IU%t;pig9zKG{9YocP~4?!anE6BbOD0M6qG$`;Z@fkVOg`pI4DN&lG#QgW2wcL`) z+7`#^^jQHMmv^v2X=xBwBU5|_6!(8o`nMmkLkU32MPv_6T zi(B!q_kX`NZRVp@cG*SfYXqhQWfaQOR)w8X2MG*AFvzgLtOvV>)ydhVIvee}?&^?x z?Q_t|)wc++KL?8g@Ja)y02XEsW6s{7!SOCbM4rg45Wn%VuQ~)YLY#WF{aThTu!dur;8qhs) z%O$4Q1W(T3(SLjtgX3b4I}T=P!!OwTLlenjB|Q{I%BKhUY)0z-DLcMg%SrhAJfXli z+O8pAQ$+c1l-kh z8&j+=zZwG;Dn=21oZVIhb1t~|X{kLqouOC~fud@m2G9L`$(d0b5r!2RNf`!vGYfa6 zd_eW>RIJCc*KW7D%!%gxvxzEaC`*E4S5Io^b6pmRCMd>#JDmW~M;C|50|W}_@rbrk zQPXLnS6G0EGOE1Y0r<&S%k_bCJ1VHWa!EoP>gookp1CGiTUdl`luKe*+EXTQy<>cD zJTD*7e;l$F`&cn0lFR0MA~(%^LTm`cHq9`hd_JBNO1;S(iW(OwFhF%ur?JBe%uPS@ zV;0Zk=Oa*tjOC6i{`HBLsHCtnnTC6ZBciiMjS~)c46f=`qr0ku;t*N#+tOnB^Dur3 zlTKn{n-J8mujM8*fI!Z;-n1ppia<_#m^iQ(*MhyNMrB5hdJs zSPDE(vKf~enp|%dLo2pjT&?uOK|4BqhlStHYprdi!PU7q?Y^<+QdmTakiZ&nGh7di zWyC?QBGhvcry`U5Rza`hRG!l|qbhDjVan-8e11$%jYLtaHEWnml;7^(9zXyXjnybR z^_M^sXNZb;eoOekzwp@#SfTrOK#GqP+((Xh3%lXp%T7y06iz|%$BR22r5KKMlwuxoj>3jv)X}1?t^AGQ_ zxTVq9+>&v{>9BJh_0tNu8YDOv{Eq8vnwEa16xz+AIlauhi*Z`IucY@3akr$+;XhXN zB_a`lfQ$oFoehrVTvDjm?SI&snQCvH2cX2=&nKGgULKSpXh&rWti;=MGD`Dm*2O zxhH5WAH|i{EtD-t9uugNAh>jY|AE}W zr87uUe&9z2W(jQB(m(1J126os69LH{6hC!9zy^i~-4))ohmI->=4O!v+Ba&1uR&D= zJ*4==b;&w?FY$zu0E{KJPIFrj-8>p$6HCRfQ7ErCgmke5FbI*ZFlcpUq}o zD`&zm$O@3gW?K|KpzO{3*%y|%Yil5;n`p>Kp=vL^{E==;tp_~OJ$HF1$@#siC`;7I z`0SB3PsKmf0(U+DxT}vqBBnQ zn+QzwAv&$$SXtN!4g6a)N`zZ{N#Q{%G0z?MQz)by6l8k4p^}A2*Y8G*zK_?vvQyP5 z1coK66TEYUHwMU#y#2khtqJH%(x~sy(>g^kJqaPZ1FhMZ2mZ`bLGZ{AFoO&^BDLsp zWD5-6@kPD5rKv{LW{8@}tb?Euj!rO>kyWXmWx6`t#>En9UZpL_B*qs=M6aPx*;5%{ zPz4@k3KGOg9Y(iW|I2%Gm}NTv;ki1@@ei#6%{S=KqpfStuq8$C@n)y*oc@rZ2w!I9 zje7$$8EQrl%Rfo!2doe(p8!E_%uuNcyb7CKfRfUXlFO1}=EM^-kk=}A{THI@Uia*N>s3I_F_Fj`r#_U~4pPEyF%Agw;ki1$ zu$!Pv?{z-MM2~|Rf>3>1{RQ7^i(ZY}l|Sir;6rP_0aq40ViVUfy<+ucK5Psu4%Q*D z!Sx)iF}`7dLowo)=D#eokV|b_zfc8eON)nI@q#2DP6BD;-!!uJgf#6)vsJ;0*Xp(ZY z1`r1aX@+0&{qEoTT0g$28aqfK9NtkytFuzyYn0ljxhkhKRWvj(&TJm(EWBeVnY5S8 zwG*6+(mdq1Z|T{^0(L9Iiz+NgHU0bu1_npzN~qwvX)32XTym=MvX+7(qNVC_u+vM> zlVX2d{gEu`)BbG)>HQ&LvUmnJO+-z=n7!5cK3bMm8)6^1k4^Bli8GdZ5(8+esm=C^ zk0sezO_7N7o$Pg7sUEKo|Hs}=gCdK~2$Hh0O4J`XtP{5swd~F~^s}32QywUp;on`7 z2vL==N&-|@VM16IC-Lfn-j*~DN~JTSf0=|Du)nOt2IApLe4a1vgW;`4>~_^Mj^7A! zsI{m3);`1=8*N6dl5Z}0f5<}F%*|T>L-<~)aW!WSqJ0a)K=iFvqilwHq6!P%|5$Ew znf`Vq^a12yBF6zS*KjkhHdQ15!E=DRQ>V&!teX_e)YiGDQM zFPcK48{O>HX?aZzp^T?#ZP+1Nypm~uYTSOXhCW_=py^c(;e~2(x$479+CALh=hQR! z#%~$T+yO}g?qFStwen_dy8+=V5wpyD7Dq>stZZ$vv0LeVBzbF2t);+`gZ$g^vmLeJoXZ~M(!`07BG;s(mOE7_I zMmI(IQoj14g>yUr0Fx514Z?Xb(7g;M2d@AC000005$h5gxSQ|*7sos1fFJeT{p>zM z7r)d94>oufvpsN@!>bCgL&VDVNT*@I`xhknkKxKfp0iq!Y#`p84Z}z^p9Le8cNn$> z0R(9oH{z*>R-kvl)j1qc52*avQL5(o<8%|MM<32+M?)bh$rX+*6vk4)jRg`*pf@4g zl9hUVW;h-i>MS>@vab&Z>c6kZ2s(8Y3O|&SBr3sWjGDyh?T!WjMbO4?N)vN$YQ}9Izs(nzkzvaTQ&k@E%GMbXFVa;Ww|O+%rlW$@SnojpnWh-y8J=kxN!0teZcK9PPy*f>7q_X<4$v8RU zR$~+4Jr{$){7roMxlcsXeBE6={)c03eX)*z$%eN9-#iIL=%JspuOvnY7lV1l;#`)$ z_Z1~~fAb({UfG*4CHGLFR-OcJPZpeVHav;!l-fZ54p%?4SLy8zK)afHj@I(wn?||B zQw9~`&-9G&g5adL!F!Q|2)E(KD?|cns6YLaeN>W_JuId8Y2ya5&Fr>synw$PCmbd! z=U+U{U241s%xtoBkfqoBw*PX)%i0AZLy?0Yw`t13hNG;f!zT;5hANqX-*<-o3a_2# z#F9>I0uXsC>=AZGL8QBf?XjGC2vBn%E>)N%9-= zF7+}y<6K@m7qNY$U)xt<^-<4=5Z+&Z7@?dm{kC#S|Lk~%ZP-20`sa2_9rWR;{I5_X zjzWa2Od-bPj&A{1q|r(WX0IBq!IBd$UgUx<#zlux<@-j=85zK@qZflt;&s-@>T;WY zM_PT4f`VM1bbr0kWB6_=sg*j_;t++R0D~-+-F1Meq1hrZM2rt<8f19+%B`Z~DQmoZ z)21F*w5rG@%m~sXYs%}(|CEYATdQ2W8<+~jjWgZaJ?Ca}25=4wo$|T?)-uj`Jpd|| z5%6yNRMMYI7+(i^U#pg*_Z`0~_4EGqMT70BcryL++`p^h+`+OCzBq5xZawrDL`%;Zfa@9qUrR?7Gqrnv36BW)>X`q{@R)B!*p}S= z5HQ+`aI%7*l*@Brf`99bk6zn0`j&K23PegB)GdlJU8`Z|P^P8c0^s&-HPY#L8{od0 zix#<~fGsJM{)gZBcw*|KUgV!gqx47kaYalHc6R_f8hgIBlmN~@@G9#4AY=YD;}^PW zx^UID{VVuvXA*OK2(i)r78qBy<)Ok<-Tk;^OLENGL8FjK@qh9WB-l=K4Tg}1;_CT?Mp+ci^EIrPfhQzdY7CJ^oGe%KcL~B4m|p8H4-IVn zRzu11%8X<-Y?3ddU$NgxAV!yn#E19HkZgT?@A4rEPd&B4JI0#^p9^_czVcLek3JJT z@r8$rHV3CzDX*90dWnz+^c?pi7PLKNXy^6Fy+;SMV7%mg6k-N!<*Z8R1M+I`W9+^y zmZQx9k1&6Z2o)ei z1+J#`KD#%92?DNmY#7aEB-gj$f|}q#_aOa8xi`V{G$4*Q&`SIN+ixSNas-A5V%3|( zP+hm;ic{qjz(vP=^8&bC$a!hn|M?~iPP#Zy%oIT&^l8RXTqG%~Wk4O*t19S3Vwf65 zmCaXYo^up8pFc7ls;unQ=Lf9&rYsIC)v=mXgAF_&+p-*&|NC`ySm);-bZ=LE%Nw+< z>?PxdHiCnI&eBC_!KBtZo&iM+@+S zWCcNWDq6g|$M`;JmWZGQ8W zFjq;<@5z%xr{Afei#->)P8) zWl(^B7P{|lIGwuP@~1GcS~U;NOvZMsqDxQ?!)};FCkOajd*e{CB%GE#?1 zXdII*S2V;UtG8GJ!!IvvR*n4vt`zVpM_2^&&jV_s)8zAYw7zv+i&=CHt%?9MjA#Qy zz21ZLBe(znt`W!iwRtoN{{V78jlVR=s5CQ7>vZgz00ggK9^qxMQnH=MCx?=^B;cM* zrbu2Ry|5dNjZVdPhr2a)!Vv&j3`6MjHZlC6?F-1}bb22iJlRSW9m8}^kX$?S4u@xZ zy>nG{AMS_F$pGAQ8^dA^Mg8>PUU8BQUiTefB7JwN`EiPDDYb75Y^y6Kq|gVdGl~O% zy7OC_GRwlg3;hR3Sz>OZ-V5Wg@ACa*2Bg1&njj3c2cBVa;9ReA*Ifs-lvM4FiM}Z9 zmb@h%J+WJ&FD%lQdoz!G^D>qDC+?g?qvy|~@M6%2dn3|akuJNZjLcv?%6gqzdnh#a zt#rz0Mu6-Dcwg_VlY@Tra%Vh%ZnJFUN=rkL|2$jop63y@D9|b#2=%&73QU zBU(yY-=E^@M{WfX>3v8dLu~#QoZQe{M0c`~W7|O95N1wY2&9}YLv)oKe3k9o73)uM zB@?OHcyP}~*MS=%>}BT{4lk{MK?Ze*rME zCSC>|6byG}NaF}Ikb7m=bQ+5Ks<+uhQUkv!vCqXr08UluEuQuvUJB5HSNxNw_JJL* zsa-TbvS#`LaLr&uiJbA#_|a!#fodI^a%A`2!tZ``JVM)e+65BvK`3_5KBM617;&l@ zeiQAHjatjobb2CM$O7nr zZtWlJlI!h(m;EUcFdG3&BjCgxfc~r|XjIvujqutyJE^b>uNnn9L?A%e&eUlAHLF6w zW%3FC*f~pFm_r6|3P>@$!doy-wpWPly^E8&%yitR6x(aW7j^|G@ww9FyoXp)NQSCi zF!(FAguT7F3=ZNS0%STiK8vbheeagb#tjikJd!9@fLs>?jWMEeRadh5lJy)8Y=X!) z@GYeE7;+D}kuIXzwsEzgX_L$hWhu7JS6>*kbyG{Lx9dpZDea$Ns-5Nqqfa_{!^Njs zEx$lh`+S~C@|N8ZQvf0cBp9WgGU8!qTxh%7-2_*^gWx-)$=skXW~L6X8I5w@8+ zSwfb?Yq%%hqGn|()4IQ*6mu!Vx|H6opAvcyyixuucd}gv*!6e%T^f0N<-1mnjevM$ zo_`LgiZ}pz%4cBf+85hd(o61$L_U^76j1#wv2$>nQ>3tDfMDJ~01Zxjn_(F!nDds1 z$FA}-2SygQyg2F-ogG(#+{Yj#byd2NLk_W3Gvs(-omxEn<^}CSWX0yWzQ>G0QRj(v zRE3=~?|t(VQ4nww-VcOpu`s8gZLG5U|Fxk>Ybo|AXqikKrb#WtB*ZWjFNib`?&n%O zCMwqyA#7?xdb;yHaZ+z_u~gj@z?k81IS@!}e5P^2h^tXfxikf_gC;jF05fJcIq@xWjxF)sqU9yy|V0TJPI`)c^w8?qrcURiR_Jqf*VxG4PBF=mTcA51C zq@F~1PRY+dlfPZV3$Y-nfGSy*^hM6c_?bWUEX|NV4u;6}Sw@7L&hq}5)G*FRYE|q9 zvZL6YwE9L3S)P>3HE*cu9^1`Dg)`)IDPOCtL{<9@bjP1os(*l1wl9A@I_fLBF-%4?|3zf^aqB6d65$f{27D07ovV5F)jzct6A|=)3-dtM z46%4zggy{#bQ|~>JkY*6g{Sbx1eOB^rHzCQ!x~kNd$RSI_=%Cit#FXh$v-I_nBGc#JNb0+Qa%`JxCbm9z*Az>zEg}?|}%Mi)aM@sW*QQ7Xo1eme~!5Wq7+v)( zLN913;E-a&lJR*$TL>g(Tgbc|-)m|WkZbEWBjRz4=+BaZ?Qda{?2_eKLv7~SWkYLo z<~Mw74aJqau3-zTxrUQ(6t!z_sme1AJ}tQUpxR-gIJOa(RvwwsAqe{i#WltIPawbL6l_yM= zcO9#R>7|hLtaUty2nJ~kG!+DfCV(Q}WLdM@Fp7rEV-(g;<}Uq7ErZxz5`Z6EH$PT` zg%Cp@y}`-db!@*<2;-qz8OokQ=MN*(X-IW0;r()hR6oEx_Fwz03k%uFNF3Bxj&mKj zg~6OJU%iqJl%3E{BU(X&_`Y~=z!M3t3wY!dtl|E%4nY9aUJ(GZ(jrrrU$QEcgTa(T z2@RwuH`l`}708Ekm_|ox0acOC{p3VpzSn79VHm;6DBW0I_MCOdol|9%r ziVm?ay5HF#- zo_j;k?J^7IFbE71X#QtkF-v{KmvK z)rtI7B7Z<4hs`^&YbM3>52$azH>kLnY?zxVU(>a{eC&ePjSxd=UyOi0)crqE3&&&3 z9^OZSCV-Lc|9n}T>2HeC(zl}eDhCAq#HyU0T8TM)Glt3hu7djKo=jqJ5ywhlghOwQ zS@uuogLBipR9=J)eo3nu40n#eb6R zECiCUQ+B@m^)GsaIgg$Hgq#Ie9yCrt-K9yyngH)1m1+oI_R*arT{C`IUuImC!Kx^I za-Q|OVcKhjKzKd-bJNC3R}6d{-iyRvm4P96HeB1Ie$8Xsto)RTC1XK+R()8(U(Sgk zPc|Bc9}JIh#z5g<{f=Hj1lr%I;evF(RJXj6=JZ=r1F7#(V2O(>U71D_KAQ00jYffB;Itiy8m`G!UP}l(%W7LQM00001)B>dY03YGdneL;A0G{3HB%i~NR43P?!wP;T zo&d>590boGuL9c|cKeskGiN|dJgrZ1P103zROC~}Cf%DWT?=@7Li;$-a_b5e$(sl> znH7+Y;$wUgTO5I_vX)c2FhB)N{P~-?S|kh*fC?P4^T-8vpo5{sDyEHh>=yi8o`253 z$opi%e0UVc14Nm9{Xrlv105M4P99nmEb()YzK;9-S0mJSj)LK`@>fnJy|vd#{_VB+a+m*05lUm9x|bj4DZQ#M#JT8mD-^BUZNS{!#>PnD zO`N|DFopDuIb#?2H`7qq^pI8^C>U1YbO{0#prF%Rg={Luo!!E zDkE^-`%((P;=RlM5s62I0w`Xm?(#X-=W?K<+^QFsxI=3kg6y5d)uaF>$zw^nh@cA= z_cjr=j1>J}$l3bk5#w>1{L;vggOAoFvQRu`*Y7+1>yjKYt{;mN+eYT1{08M*4Rp|^ z7_l?=I~t|Bfr!~j#HRk49naTTw|lP&=gmDVWew1Iy#%h*D$!RMo@C%yD z3d+~Iu{xItcTJe^)f%&;mMb)#lPB=g!|#C)K%L~V%#}m1r@=?x4v?SR)mgMYU=AyN zW%*D;Cq5ZXgM^O;>%>@gW1guqtF@S7Vn@VdPhXv~Yb{<528|ky(GSZKA7Zy*x8Mdg zyINWtckTxTKZ(zZH?IC|fBpo`s2rL3`+934vAMDB+)J^qjOM!GXpLHo`3l-`+uVN2 zcCD@bFEZxwf3AtM1tF>J)m1Yt)kz05{PG0F`#!y?!J#@X5cY;mu$N0HbdIuOe{mZh zB#Nq@sWbIGeSK=+bzfFmQ2%@G+#QoS*zsDw6MktjC~-wK3R?X@!yWTU4!TY|`dWKM z)YN*lwyvVuw#klIo5{9$KWIx)XILumi2?;26uy{$l4mU-yee|EvtFgcpPmnMwb%Q! zBye}H$dD}pG_Z`Ye<@Nrv{sl58u8Sae;OEb;dB4ifdrNUs)oA0^XR7W-c);tg575g zG_G#vp{b>S>vBg>1ngYGvf!U{lKa|_Pj3qY1xhR40-umzrIR#`l>m;;;`u!x_}`T4 zgGco3uVkgNzr;)Y!s+4JcJD2&zi`_Wndic(-Ye+@>`Buh2d|jjt}&cY;hX;%%LILY zxXV+ABbpmiXQURk0TJi2lF92+G@%)-O)HXjD(R#YWHkj=^H32+$JD)GuJ=CDHy2$cP^KM?VulhW-9 zP@Jplyx{2~DxjC1bUhGKhx-=}RCRrym~M$DlO6&jCw*~ZqG@?;h=F9ChF|zjZ(dju z>+?6)dV-*H8;fP~ty|t}DY$Y%LaeK*>Ez1T2=vAtmh{|9)e5}5TeY;TwF*Z)KgORt`alRGm=kR%s7o4 z0=EoAteJdfs($LLrNiaIeT18D>vS`?($Kt?4adIJvQ!O(;r_Aow@K@ZHeA^ofkXH^F87*-1VJ$tiN7T5VYgU`f>A@LAJtg znB!?4d~16^l#4CT>#_w#o0JE%kw54N+A`HIiVKic&Q49|-{1U&VFfB}diEi47IGsF zLw{`da20S`@E=WNW_7w3xZR)YdSe>t_Ws(;QL4;7vvm z8oZIYPN2nHT`&^Qap1^57lgo{X$*?q`9cZEb@PVZ{>>>M65C6&8#i8i%%rBC;sUnE z$bSeI21?pT|90cC`L5&cTC=-*1wo_(pSd>8(?3B&!!-qK%c09ll0t;$Q@Xc;G<|W! z)F9s8abR(Sn`{_or0 z`YiiA*FW$9@C|pv+eG34I$|8=XuB)8h<}dVs_e5;%>Oz2xD6W@v?68E?7y0G@TeCD zm`UK4yqB(_NC5LEeMgm5UHOF_RUJk@%j}qI=GvW-`rlL^fnUYnoo*kOUB( zl}=OZyH(~j-+8*${_J&Fj={~EF>M#cwv`Iq?h+1z2m?rR0c$y|JG{ZNiZK7=uEVcD zMl0t}l;90&r%J3hDTkf?MU=@Glcr87Hrd=J||GB?7d3sAY{m zO@yoCgUEwJEo=eo9~g0iqTIZ8Y4+*aQSaPwF@?e_j>Qz#Tayxen_0+mrw0&49~xuFaNgwO_yW4s!rw&+0PO6%MOK`FYb$0eej~TSmVD#iGBMBG@X|nD2~~V z*n@Q(Wm1Vv7DeJamkn=plhS5KO<$dQ=9Zw63`MsVD&5quw-(~*>R^lKDJSy$vQQh% z95MMPOsqAdZ40^0;0b{>We@IcC*oXO(Db!&AToA=hUvctmaIG1%{=QO?m>>W2OB)mj7?nNq!Aj6Zu z#`v{0i5{zQXH6BoeM?aUIcgL#!7eXn-Y%YEk{hMs9GqH|% z*RVResNs}HUdcdjPb`erU(HGFVCcE{JIUjmTE1Kk=M=k!&hbLTaYA@Mcx3Z!e4XNv z=s^1V=CL?&fOy%t`rYfAm9u9laG<|%zhPMCZ0?x+sB|uFxo23Oh48>H`Pth&LW`Av zRWJQZ6}VyC?l~;lFqjw z{r~5F7wfQ)Y@KPPGWD))dLJb`bY)YYyuE4>n9w#_f!*VRAqRi3$-#WoJbrnpnh89q z$Jfjdd$a>9J4JU}yKr`)KVJ0dn2eHf-90YQOe1rLM1cm;*(5Ztv^ z*p#N7HhRyqY44hB$0#l#OMA)2b7(7t-oy16?j|)fa=n6E9mz-78Lkm+#)PeMEvAYe zhe9;-hnn9iYGs*doxNQQ;2|eGlCwPI8sa-x;Idl&Wfd@aq+o#%y13$-2yxx z(;`fIX+&ERpmL=&t5M3v+JQ$hW&9$-{k)8RVF8uJm_BJL{6@se zw||pxEXbC-knyUbDR_o&D2-P<8G$&m;qcxJ$t!zT06tBpC8(PRcUFZrU2mU5`=>bc zAlAUvJzcd<#j^ITkMnJ*3ptn+=>koKnc*@42?)`+IyvJWelyrhbjBOk0~UO^k055t zhlg8x%E@(?HoFNTc>M3kSfz`JQ@+P4@`2SKfTPTdi<9(u=Skp#2S;2aMw3@QtM%ji zV2v~N?L_C`jUZQ0KiKQ7qIq907mlV6dpAUiYTxf@Z|zHgBYVc<9kJ_RcshQlVg^ht zP9*p3@NE<?B&j#|f*FrR)3gy`&kTZHIjAPZD8?Fi}zI%a9Wn3Zb z<+)GI>Bo4+g9(RSWfb)7cJ*c@#zYkf=HZ@KOaHHU?{xIAj}7hM+xH~CztQ2EP@Yk$ z!4%xii<89MJnroUl|Cv4vVA-ho-K(V51upBI1A8BK{@B_qc=n1b^>!CC9q@v*l%V- z1XTfS;!*pTg!d5WgJal^T*q(IbSiqHXcF?z^u+7N6U1dYDdofhtl)>IfMHi zzf*h@<^dxAXJwRr5z^mW5WgKGmbQ1O=EWmWCEa~@)?$)Ysg(dqO@*EFHSY=GD&|!6 zocf+TW1kPhJcIFpKpn^Xrh`(_^<%KKafi>6=ug#zKy*#8{%GEI#0CP$!Eaw7o=WMr zjKDk@tqJ1SS_Ci~jhWqdE>!TX8+5y4?J;ApE+c8*ykE@&a=hAnpi-52Q?geKaf^%Nf?pQhQO(&$cs)eC7<*yFzN9%UF=2zZx%2SN-ewPm-8?Ms+S zPd2Cd_AIpjXSiej1bC5~Bj0SqFJThXlOZ;$-jWjDN*25JC~3OC5}y;XYZZvA=b~w( z7Ow-vNvAJ`xd02Yc|RHHWk$9lv1kJNk*S{=BjtlwQXQehV0v1}I(k)AY@a|d3!JsV z8G?`%#ClVogM)MsD|r)QnR$ykSoz;KE@?N?14=c@8t_if4E1PPh{OXKsl{d z`Ql_YveOqGuGb23(WuaM(89H*b=E4v>~OtL(IX9tecAY9yQ-yWp;=q%r^XWAqPrR(yp>@n>}uPLQaB zcmAYB(Doi2jBg9xn|>$`l=f&|#xqhCdwT$^bgzKxjAR4V`9%xf!onrRz{u6|COwHd zYuK&tHRf0HJQzc^K4?-tY|$wu-!&DO^-$dhHDH7fu-fS#7;oKC2WzXwJydJ)4osV9OYJDpgs*&EkkRP2uvw_evn zp4|mFg}a?ZIEz#h@aq7r2;S!NxL~uoOSE5-KUk;&;Q<5N*jxa=q$u9Yt5A|l-7O}1 zKK{SZkxDzs9MSy_Bv56snbCtajtFUK)KTc+9Z&B2d~?&ZwY`^-7WHxzPt1wHMjuTL z=hxfsMG2ot`YxLu7y{f%PNGG~M+tTD(C^Muz)4pgza&Mhu zF+DyYKe-$nF1 zgG(WWX82s_(RDoUAb7~&;S_ftk8BWB+>vG4xp~^oS54SQwSQj?*OHSe3NoRz=t7Mb zlITb(uBNsdH$Tf};lKZx)YQ=WZe{kvF({4OU9lSY+F9<*sRsb_S(QNmSYWVBRY^|} z!ad#qm|n)Fei>v@gs72h!mVlzAM{0}fZ^5MH-g*L4bth8>WzU!6W4twDB0tg&ZL0* zK9jh^)7Xy;%p z*i2fIfF=P*v#Fyh1H4lNdz@E9wyaYf%`wV99tinxFVLV_J0Tc?cY^$0!rChu2?^9U zV0eP7VB>W;+GFWYkt#35=Q%zoYv3OII*#`n@QU|Cd9Ix;PJFpgrL38+UYUSe_}lI7 z+1PW+UNETAdFdqCMT=7@t?T&0zm9nh+HHVJ_t!>WYCnj)4bq{Cde;OK2OGCf>;QRJ z|El1JxK(858b!b<2|1;Cz?Y$`~a$ryqcP#e5GV4wJ5#OTV_>x|^= zGrJjOpCcjM8G9x~YnudbXk|PNIq9^mC)1ed_Od?7sK!9KwW8iuyO zv1~bv5n0r7W1G_L27R!)w_4T_?~Dc*qK&Hc20^_%%qZ|T=9y^!s`8YXOCyU z>aK<3++im@(Um?zaE{P+8Y~bNX%50f?Q9K?9T5FVGL1E&QZTAD{egu2ua~Zu5`!>m z)2@}d=Kocubk;ktmai2Y9sO}|V`UOvl1YmlkR&-PgMm;QYw$0o*tmkNq%|0u#nqmN z`c3+B;d{qVo^WZ>lIb};Z*S2NHopEx<<%WNOkf}MxG?szjJ#(4RQ^$rNExkW1!?%z zsyL0eYsKS1`<34jMKERe{hs*P2}csiBP?D*>?&^F7(D1BY;kCErGE=T4`eKb{y>W1 zRHEK0am3$Ne$kd|3L+a>+$c$ywy2o;y_~P}7o#UEhTTu8x@%6g*Sn5^Jo71t zuwX*3s7lN`v|=F{CO%>c{Sx(`AR8dhgTgf*u|1|?Z#)WJ8|eV=*1a*}OlhGqt==Zh z+`2S>9~;46^KFGmgFJNU7DrjbMZ4%P?oPBI4?AIA#(5O#q3123_ZEJi!f|-irl8;e z39Le8>j>=B0&dQ`oIip2?de7WbyWQl+^w`KdyrqzZ&6`JmUQRhF9Uz%ws&IjBslSV zk2df8ZYJQbw0kSPD(QTuP)E|ZZypy;P+G9h$PzJjB4W?sCro`e+JCuiYBwIixCJQc zm*oO)8=_IwqXs~3P2-VT@xT&Uyj%R9vo5kJI!A!@QO8#lSY#VAD-|PFtJp#QH>P(Y z41j-st0L=Jh;bo_rl^Z>r@+@j7BIY<)v^^)p{2clh`8Wrn=d_AU8(Z`kqG>*$W_%=p!7o!I*@3TcAEpl3+-rx{F1 zCytaEuK)l?{^t3L+hgxK2D2sOICzJyq6B5o*$`s^lk`S7^_{Gs7o0^ivQD9<9GXd9R6a)s!-AVlB8MDHB8|c0`0KWZ zO6>Cs`0CdxcJU$7Cd##mrXVTeKklvVP4rJzFb1c79zQ%)QTE5TEVp$}4r`vyhFIB- zoqwh$f%;+wTN8A0*?%%se&z)VGxiQA5l%LHc?dh04BA9%&w69^ZiVnw><^GfKu`Ncgvj^7lnSZ4vR`Ts-KuN0F z9g&qv;v4DSNtY&GKuq57D?8p2miXk+v&szTOfmrt<9D-C1O+MWn9=d0=5X~>;;T;U zh78#|L&^(Nc^<9Xz4yfPK{mw7vO}_TQm$nrl^W-aR#q2R>$5z2J^xj7FCOCwIqr<9 z@)Lx1gRs$HfU`(;5+`e5Y;}C6naIzBP|T6IVLxM5mXFzuW+&p|L$9CK0SmRF9Y%R} zj)3&#IjDzIcM$dwTPXbQ##E!vp7xohrF?RSl-rA*Np>zRFQ>`@tD67Y2n z#R>|?CZ0a!`r-tvqtW?P45Hc{iz?it$u8Xa9C-cWKZv5`Vl3$jNeKT|z~*`maBj^G3_X?6ILNu&)_XvWQ{1 zHrTH0uzBz+;Vla1H?qG79Drq=ht_7B(2vi2z&u&C==<91J=7iSmMfm%ye=mV8b?s^ ziEMU<=kD^&!IOAQ@GS8V6mzy2V-2s9MrM1xIlKKXd$0&W!K zr?QXOsQK~lM2<8OrGP$E3jDb(a+TT`a;T4WwQziyD93D?{OH^VOt^518x3Mb$fjq} z+@oqA4YIE$+hk{+FF)R4Vudycjlalq=~LY@II@sRI=kR^CYWCQQ^R|s7?9Ty-iKn^ zpc_5?(<&$T>i0KgcQ+Vk2IbY5v+NWX{gW>Xtn*olUKb68v=5rS1YwXxN#qUrKEL}bfsIm;%MlP zjZYRT=Lkv}OEBURR{AKCEZ69r1+E>Npp#?1{nBWViI(}+qz54#P9=B5ySB?^@t@^n z-?#2t?*GMbd7cQ^c*uzy=nA|aZwwL2WvalFZ~VYvt3$N^V=t5twS$%zpeQCk|0 zk0Vt^`8SO1r#+)9BsWTX8X+47dwzJ+Gs77`(4aZTi>@b{VPd1Ji=wdfmn zr0;LfwGMqzmi##SO}Vs6aTomq>qY?ZL;mTe00MFYi7xH{(*s!q(VYGYCfHlIAUa-h z2XHJgr)(w2IxmDfK|b&%><#85sAj2#x69wxHdP`Lc||uPr^DL=wcUC8ES9xtrNebl zN%@0v5&$j{&DrkUut?VYR%2utvXi*W>#^kW_S2CuOyc~%xDE>J1!IAx4zoKd zbTDB(?QJdtOr=`JAD>k~@OJH8WrY9A2&4vfu%XpER&=y*w4`(m6;9Yl3k!1?ogTv_ zOJVaY*Tn_FtWo-S9qtCj>VIhjeUy^#cY8Lbi3xBN%zFp{;RMv$VcXd&G%n}6BX;>x ze2m!a9}e>%%po1S?Ip#LW%K5K_zo>qUmJz~P=`o*JN8%3zZx(S!6sxq${l-jd2Y$i z&tL2Tpt%n-k8xZ#gjda_$FRUw%tAk>C5Y`B8~YBrD$u~W6SrByLMA|8pE4r(8MD^E z^3tXfG@x*Xmr>>>Xj1Q`!b|JVm}$=;ATdWJ2ZYJHH+Dx(v*qd4FKVm9otJ(XN;gjp zansvz@WTL>isGY_q;p?_IMRDBwIx7&bjO=D&L$-%?~sn<>l)IPo;A0Iz!YgufJAPu zSEld^hdwB4VG^^udy?(jXzc@QH5X3oeB|rTxUsiE-pYcaP6`G`yb7y_sf1NCev+bH zLkhA5GG7t8g`{?8)Of%C1F}o35Zmf=D|8Ca#s#3P<3{&N&4c!T@VV|5l zWdBiAt5|yJ)!Mqh{3C@2-pC=9bS*r-I=2_hd~ukknHutAyb=DUI@30Yozei9%j{C4 z(ln$9y~}2!;*Q+X!ynB1o<xoo3TcKsR7$BWX*$)SG|9yhJsOwIT4izhJ0-d_tZiO5ONH*?EN4 zA5@WwF1rB#5_<8L6m}BZ%bB>P()-Dr(kid+Y#_%Z{I`TL1BG_| z3*7yMC6i3-x0jgxi8ISOnZ%Io#gB)lUqt4qzvdi-RTAm&pI!CJUX@aTY*o&Y4`gZ}42G%auzh)}m z0NJY5TGj*|PLkIQSp8Mu_}Qb=ouQFAvVu)iFVhM2VAP>Qh6C3`3dr2T?OxY$Y_JE;srb8sW2= zI5%(q*z7h3>2X29En(S7mu2KJW<7hJloQvEL3?_IW_MX>UF5?tHMGIP$wpx+)5O{t zmY?LHLAzx}Q~hr4v9*-j1IBX-0X)Nwraz^LjC4j&?QR~% z>zx)KX|OKpIODD~FEfpHYX^>-D*D1ZCXGF4Jf9N)SWp9jBp?@g598|QoH1zKFgDB= z08|=u3`Q9`#sV$zV{T^X3MqD*O!41W*;!v5KrHh(;`$rwr+MkQf4d*gXAq-uBc~U| z`mAD9A8vX@(uKMf7Ag-24R!#mVnAry-Z!eLbQeSoG3sO3rFQE|Za!8yIF|obY~B%H zJhm36>J5GBLKq&N(vu0ee+MvdqlU4{BD*~0IH>veP8SJ!U%x+PK~buc4J5$3e1IOw zYk457`(hbOri$YLK2sskM^T$;CzkMcwM%}b^j>AE*$K3fllK)vS8+{Yh~r7@zSNZg z@zWk`*EpDzpT0snldNk>R&}Y6{Z2f_3}&xXNpYK^<$MJNVj3+qgzJru8ZZ?kAUWK1 z`Zw`~6=?57k2FwiVXfF7pOrylUDwueyF&-8Dga*n*+lK(q4IRFntZ0)Z0>g+pv13t z0oHWpN~{C@h&AR*O}FlAf=4xwBU3cN)7SZsdkzbBotSU9?3Erv!PztGYB;OO$#OM= z$_j%TG^`#(c+Loyog-Svc!HzjHLM$CWMzp!Gf&zG=Un{37FNq6M#mwjeI!pCqueco z(JLyW0x*jx0c~?(`<%TfvJ+g)9~-Z`b)U&F8SmH|LTh|s*pE5P$KbWtQbqz4_!>bcBTHqcE{-LCW;d{u+x; zg}?=Tu043}KE;kjLzCR-vtR0)%jj+`F;+sl+w4TpVr^_`jdoor02Njggn9*4Fg|?O zm0%;IiHw`$T0lv)jAabE4em=f2%WAX_?6G^2V?8v_R#9(F_n#6=>1SrrkJfQ=p8QN z-hx&j^Bs(fvHaKUrrWv}MO;Yyd8`{CO$?U+ui><6&(|;urm5E|^F05|BT4<5l9>7* zCE%EP)$tfCaerIH5BSzJ!_tZpr4$fIJn_8CF>g%_uR}nlx!O$iXU3KYu{O-odDHZ5 zw}d-%)3oEADjDVW2Sy3YnZ+FNocYQzEvj)M06NoAF-y))@Ng1IZta+u-dPCRl4}-0 zSTH)HtPr);$gT^CDRiz@I+iVp~^v) z9kSGSwAr|TfI<&#Xq87XB$cjr_lv>mD2oyY=%nkG`7)sr&**Nu=`T13d(HC5LYXrQ zmlCQu^d=`63$vJiIQw%LogTv_OJVaY*Tn_FtWo-S9qtCj>VIhjeUy^1RR5C^uE`5G zi-@8-)(n^;(g>^*Es7k4uaVn_2a!nlBM2fBkt{y~c_cmY<^Mi+8!L?m~s8^;) z_>+|Iq&g70)KR^7iq(lArGF3s{<1`;Je!iA{{}8GG83j-?CHez?fT;^8E34QbLza~ zn|2Tr0bEu>lH&#bMmcc>Phr+V*O5sxBMTw7g(R^OoIZEAqE15QDGxriSB2wRc{{9YjbwCRZj4;!PTJ9L3zE=}jEj#j!DBrzlP z&K)%u<>yKT{0(5D?mc@TD-ceI?w2*}Z8v@F9ikKgq&_(5?4l8|ol_I>cJ1D=yBJA} z>{ItHK6Z^@$chf$tJ0S34>D6<1i>|?bwWhquw19jpveD?P7VLBDV^gob!WSh5ocqn zy78TYwD*xTf|v@><#Qs4{SrU0j{BPJUxOM6=#WDKy z53+9Tn2myrWnDT)Dc=H@)t7MiVG?b-@<-motpaQWZdMqqRfspU_n!ATJ9c zWx&yRLzfYsb@mLY74CsuFE3ZxNe~%*D+Q*F8&ba}%_oYmUOgE1o3Fn%Xigi_Uq12G z_zM`SVFNV-HSkJEAL@$Fo)HV>5qLcd(sxN@XjL~4T5?Kpy<>Ac7D8 ze~EXtQu)1GZ*brM6H=cV6Lei@IVGSnoDb!t99u744e?3SM+G0(X+V(EsU#!GttG;W zZ-Om$;S~(l@e*}$2VleXPu_wJmHu7J+&8{X+1y(g7Cn8=^z@Y;!;Tu1TCE$3;E|c~ zW+oOdaG^i_Zu?yR{aVY*OHo+P4w;>aVD4i{^0rZg+^96DVhc%_y4x!-=%XU0t$1%6 z=?7PxeXh}r9I~5vOd%j+XTsxOxE#@3%4e)u@Aq|20l(ww*&_O~LHjYGn`WGzNlKKF zdoa3p88Y!vo3|Q=#MbbLYwQf=*DpPwkMYVrg=h^X(KFYxbH*DDTK{Mo7+oSl3ltcc zv%zjfgX9w6ngyCZi&d{HNuIa+IfLHtQbk19o4x)gt`bQf=$bN-p8BCedgaWr>~p;9oGCSQsEyAU z-JVFU^9Dc(podYAFUN2#Z8;wLN#B@wyAuydmI2sBfHa$VAp2>)Mbpc>82E5}YnT^t zJfENTD-rb=nIIkhFt-$TTrmfBbHQnDsaLzSp|Ht?pUFaP_Z6MtQSByQazLW|TU7rI zQf%2?>Tp5D!F_M3136?95z8d@j=ftt#Q>xJ;59)VTD*xE09jdOwMWtq6VWhuP*KwSp0W}`xg|hK95x3u25B|l@0KP%_;?Mk&ES@88!#nKP9l^*D$D7N z*L3el#{O{GCf$|nGuqc6$G=s{}eWZzE)%N3k-z??(ste2_A7vD1q zC;HObg?jc>833Qw958Qf5F_5Wj4jOTNBI#Nz{Jabspq`^?z9lXjsEx8+4AM{j^&B3 z(=Ayh(^)Kt_a}+)wqBX%!T9fcbIic$IA7@B7utZFX-7x{j~6Q}jW_Yh^Jql9t8|BD z5H(?Ox;v?iMfT|g>aQNbCkL7|p?z7cjJnbfQ?prp@xQRtLaWRGBTbJSekuY_Y)BVr@|kl(C7IcG~Wwv&pLIZn&0zi6vJF=`V%2x2 z*`z#x5u7A$OUVH@VPz=Hp>M{r0S}$Vh?N*15eQ3nA%7f;=d!ae)FlrL9Ilw}yHaOa zb5j39Jq{%P#+x=;8xN2h7cn}vH#h|9hYh2;Q(m2831}upF?K%$JYs6P6xcPr*qU8F z+E+x}0Mb{Ao$f+cL-BLYDjvrJA4sTF<_T2IhSg5=TZnacWMu7fox?lDS*zCEWTK6n z!Oca|@Z}62&MFT247-88HadNgwcVSup=n`Kx*2-luDJ;gdeF7%X(8SG{K&&DlZJO- zEA%fB0&|y<1>oUvc(zmbyUSr^)2c^N$(p!~fsotXK%+S8DV{4M){_s%@oGXtxf|K}}Q`q;%F3PGi!{rS$Y663P+m%Yg-8^HIE>aThXDTySUPHH@V&ELF6k_sU1!}wANWz7c$VhX7R zR27505Ipy-df61mP2$Dd!nCwdzTA&pe8*4GQwFlylbMok_O&>}$;!<)_^@>75Tc1! zT(&I{=b86#E7#jj&U5Mpxa^eRZ?_#h2yYSUPPz}V+Pypm`6XfW(u@mqrS26frp$oP z5kMgGVFUfw{TLnms2nbC&;%@?Ih)>_ZU-*)dhz*TdZ^{}ma;IQX=SF{YnUBO4u2rZ zoEE#Y4>A(f%P0EpM`L%KOC{Q>!T?LpVU(fFj3gunl>+*j$Cz~x0xYkB`zqA1Rbx%R zy&%_1N+jTswi2sLD$|1Gyq_+KZN8IsF&1SG!H&L{{x;D~O~Yj9cSu?V@Cl;`dPaSv_3 zR_kCPNvy$+_yg1*Y53ZK-~Ka_h^v#>rM8CjzM~(L_5VG;1amCp=XvsU_S;=IxSz@- z69svw%6<_mjFlf=_K>X?^;$^k#F6?2NveMiXBcNU=5US$xE-KdtE#ZVrCp$Xmn$HH zF?Z2%S|K<*n*$>+Cfix*g!TV{zuRSh*k^{2oQ;x2o>s$>S2z|48)LeI92W$4?i3w< z!L}C#-GBS4ecZdf=h1W-Jl6GgZny<*`c(gLIUB%^iT(@NBL`4_%-QO6+}7nxk$mdl zqCt#dO=!qz^njfIDYdfj>vfwCl=n8ZWPU5yzKOl4g^XeFl$}F#Ccw6Z|Jb%|+qP}n zwrzE6+qRvKt&W{^Z0Gj7Z}w(yUXxm@>a41>&;E9x$SJW*eKG8Xev#6-A5QtXCz>-!qFFig7pn?SX-L+GuZ~TSL3DJh;XNWfuoc8`!~!+$Eg_5m!JJ%c~Oaw)S_`# z^sYwHw?v+#>}8!UG!#U!1E zxspnjp{QQsD*o}~<~-Ip_rs#)QuV`rh*)Y~aV0eZ4Cm!+moD3yN}l>PAnna` zb|i!E;S4OLeM?M!J+2RiF&SY*UbiVAbMir+ETig-ntpPuoPr|gY5`iI)^`DoT4F_+ zgcx!qOQ0fgw1AjdJxlQoG41N@YZ^iSJKJ*lBOCBH2Dl2~3kMJzEwK!v@{i;pYjs=F zbha84W-w1YldH73>q$Ns>w|5JC0O*uEyPzLF=g%nS-RER6g%Xb~a%aoE6GjYsz&CdO z8Dxwg$eoZ~8_>UC)+BoNMY#I25tDj`{t;fxW~ZXqjliX-SeHAAPUmIPKuQH}M~(wt zVA9=@GiPE8t>!Ml5C9Y0)xl7u`!ag)wcSy#M)6A17}1|+*O1rtTMLC)`uK?(ai?g$H_cJ zBQ-NWSZ$1_=rV^Bsoh6zQ(KCC?Ozpex4)s65NZD&&q}{zeHIPM{XPC(_%yFvIE);i z^C1&@3W=?X^d$}*%nmB7ajX>RJ#8uX4H37ov@99}rf&Lsz;b!Mg><{@8HUM>EPkb* z!(!@PfoxR7;CuMwbKw%mFF~A#?eqbs@s)f3xpJ1wU)mwa2<`L3vH^-3#^udyU56e~ zqLguaD;y!Mq-`3{DQ6&6H&M{?QZBu77AM%Qxgm)uYc3OteCstp!g%;EqHll*Z=65f zB6qk?Xv63pA5nn2V!EjM`o@mH#g#O@@!Q74?jl(4S~1ob=R9ob8kB>bIHA?IQRk|QQifIu57v=N1ka?1EJEu z>Qk}Yq5DdtHYMCoj9GupkS4Zn%i;Skme}cXLWWYG=}Q`n!FuP6MQbi|<)oWCIPu11 z2uY>gK*fFyLOc#oni3F)rt;KNm3tCmtSn4Aa-YFX|{s5VoRYbj)pOAj}#6OK@uNL@s0hEP?CaDB=1ytTV*Qpve-#4}CrelquZXs%e&&?`TDDd#fB>H8b%O84*>Kbr%M-87KdtyZs zi5||ka2%&)ax=nkiY(x0PUYbbc?pGgtGK2M#(%3lTZ9AEdRbI(iTBUu#OhAC4}qbS zJqD+cWHzichv6jSqzE9y1&k)-97g^1NQ7S#&L-8nn6H^{$SR{#VG?SH<7=8x9g=lg zG>B%J4b9Rm3|-`Bk!joJDI63wvqoACIpx-onl_!HX94NeFW%Uqu2g-H7_wf?hst!K z#Zq`YMM*SNXC>H2d>W}K_LquXg{hh#+M9@4u*NF|9lr0>J}MaqP^v!X3IA+-pM|(= zK;K*W71lBBMs-B);=>X4=xHHEy7^Y_4Fcx)hHmxt%&=TbA)V4(>(pXmv?@;2V{h|)nH)tZlj4$Us zreTFvCR=M%x$6kY34#MmowBEYZo~dKCP1WYGsOL``u$%0y}N?Y^UU_fpYfi})*!vB z=rwrGR@mo!^R@kmGh8cAbsS7jv{8$)ka3hKzn8g&zz`eb;Td zQ)mC)Nc7ebuLq{`i=G;p>q2RX3WZ290PjAFX^fz;jf=FzzxRl7bV-i0?2-1l@@>2R zR4&IvZ($!ndbjjx1Qgxd5Y@wo8G=?!tuY=8AVZ|643I@($#EP9TZbD1?fN!#9wT_W zCG=LVYr-rv1c|?-5bPk0vPD)2?lPu#mgog8Fs{>J)mxZ$cR>e2@H2jn+XQa0i2V1X z4`k!PPI$yl|8gi)BQMGWRmJK5R*OIeJE4~2{?;fyC=jGXSURA4ozR@2UIx zp0J^sriavsAs&-NQ)fWP&lNU}Jov$xCReq>C!rAR1OIrQI0KY;$0?pDLQ#@JSuj#A zy`^t|8%!=-pG$P(qDwuJq7^bz+Q)1sPAfypUKw0Ti&D((t4~-?ekCS&<3t!9EGnf< z{?P9e-_4jCR9&9EZ=wi#iIx5={C9vx(C*?t(|)d-7EEI<)?25thp@SdmL9?Z%>(C9=GbSXhYdjW}ZXpgw{?P#uti z`$V|9L1{pe+*)`C=tBTZ283DEJ9U=ZcCgkV8Hw=TKyhKY$v2iZ`R>2*gBB+Er3WLv zqKQsg(X~X&t!0LsWVU9;dWdDV8hd*}cL!Z;U_3aG1uHAy+*!v>{dFD$sw6|qacM*s z0eu8weWo7<$x1{Wz4nR3v5(b1&CDm)DX?1oG-p7J38-vdy{$6mGofVkPC2DvSE&(R zj;%QI45;O=lf;ETt-APkcG*o0Z zfezrKFEwjp&`k7!NmjI;V%!btkZR>N6d<#WVS@#QHpJI60yYC|oVSlC*6t?Q@j+EN z%54=FiCqGszpI>@9lkv^2B&_1Lb_OoLu|@43`#m$*4#3IMzKbIL#6CaF#sJEz*!Nw z<+Be5)~1X<JOs`H5KUdSyasGDYj2jjZTexKjfNfUZPo{}w^^Oj0iP-=Sv zlL`G4C>_UO_3~sHYLhL_zfg_~{GvmpPU95%n&5Y1`KaJxOm6i1s_Z&bw(txJ97)UMss2U}Ki)zCIP&Uz0FZ@XkFkC9 zOl`)sQ5EI%6tvOO+6`+u{dX3Ajp38s3-pkXE0Adu-xFMt-9Xcz;j2ocFrTe1;6Wh5 zzt=u0-tt5xjyqy1M7WeE7gkt?aM6zU-j4b<%h&ouy@G~CSK^bqtQhJGb5jU^b}`cJ zi(Mf@*angYly{RDa?+c{p=a&vozs`STB~%0Yj)9{c+YA*q=KIf#D|C;EtFj&eiRI1 zR>Eoga6o@DRf?X;I&ShwdIOa7dHZx=RedO?6NTRxYwaDJnhu7>_3<90l6Ahjxz|A6 z1XHfsXd#Ax&ag&+9n8;`-ROvMdHmi*p61S zb>xk$z+5(ay72WD6}Hzty3Sbw4kyG&sY7_$(^Uz{L}pO8!7*?Fz8v0achc(5Og$3c z0%dKB*-Pex2z<=7GJ}mpd0(HmcO2<567e=R+zypI z1NngL($1RV2StT=#0*BkyRS7ELfl>hH%jKIUlk;JLHc%?!VC9@W?^#>Od{g3a`BRA zFTq@RS!!!PR8I+Vz^RKF^9;wAC``|ir~N3n8qT?Ubf;29)A=MG(wAhGh$7q}P3yNT zkS^`19T;;FhS`&{nihosgiSP`e4otCP?{E{9s?X)g%GjIUs1*t?w#jN4jXE ziz~1MMzgT9MiV}t*+fY>MR~NgdrKw}d=_E)yS}baG&V&ng>mUMwEUS>IzGpgH9Ze9 zlpI;ihrVzLgwqQPwdt;2f^Rlt-pJetpDach4DgTuMMVQlRd9u86sH z@J!=N?9$tNxcI8@38cvpsmU9X2y8N|M)$6i7B?lSEgEVQ8FCinvBrrU-Jqtw?eg*4 z<`kRk(luVeNxevIf|R=Io(rm}4a0CI_Z?xWe}q-lM%QT` z6@f8v3Rfx&@JT$pYKxn=jAC%UP``H0nKK1Qg#WV;e|vpnE6`u0 zS<)f3RFT4@1nw-1$XJi&tbHybyZt>$TWM?13`4lUWZXckx^jvgmE5(~h$D4!Atv;D zxb&zqK3i*Wu}f+b8A#3Kas(xff+LQLf9m*c%&!8{O$0q6IK=Gi+E_WjS%QPEQ8QGo zrWxo2yn9Os^RQnfB2Q?~(p2v8klQO@fQ2M(p}w8ojvMmk4bvO zC!g<_Jo2EFIFk7u-vI+UW98#$pYCLUcQPra3uaT@Ni~3ag@Ls^tVJQ%2@>L-V#zdq zWPuJ}j7gp#ske6~n5oT_4(WD`OJuTY#ADC99gF6{B0%)wCXzm+qUg}H8JcZzrmz^n zM-a4_FlKLsB3udwid*w&BeO(4o5nrHzu+Nn@o1w)(Ib_PuRAh=&s#Ce(x~U zvJ_&*vhK6YGF`J@eudxJ)nekG{hF#}BuQf*Ni9T!eNb(F-WB>GZsWHeGRcom(`kt_ zk$OEBn%*9}A7ODv9J4612kGrqPhUF$CM1{BOyW_J1Vqp6--8~Jc~LYG336_j(0(c6 zwjD#wt)YLFk5ep>KVDj<&h>zvLm7zTUIN!XIPu}c4j5)G3LM7H9jB^t$xvY~Fg@4hZZ@bzbN`TP zD5t@`SFX&7!DC_Y%Su9_wEfoG9Xye47n8cOL$z!)2HKJt7Yg(2xxd@>^4g;riXI|4 zanf?es{5Pr<91AI=l}u^%VK(K*mR-N{17l8OG(l?nFGpytk*Fwyk0mykxPu6xx{aa zn$-9z?`nGf+1fzvJ_TVmKYM#qVzw-VAHkCS2!8w1XN)E0i#hoV1PL&N-S~xB_Q4SX ze$V6goJ)6hEa!H>#JL6K-i@afmQ^dJTwKMBuQ0o8jZBDl4lX)w_yp4I)XGyLED*QDxz0jTlnBbFks{G4`9fMGF0& z0)Uc<^doBo)7Z5s6+oSPK%)<;Do)%0F-s!ACFC`5Jebzy8?3b-t0mpt@f#&e;?@@x zq9A$hU5KZL6#lY6lrHSFdSrs*rCUn#EwJt|_3B~l1A(hIv!b*`>VylYDsnf%@?7^X ziH-5iGJ$8GTig^buLQY4@ov)qJQrg*8C?10c-usJu+iYu{gpGb2GnN`1jm zCXAe7*C(77RJhlM4_=wx{Vf7G0k4eO3U(U-!1%q7%^{*Ee7;4EzWmwH+G_Z`_m1Cl zHhYTRA4<;nZ0vtrp%oIY3SuU}ed+j}Cj!|+VTq^AIH4h(f4Qrylklw2_iTBqgA^2_;1=7bHm}zk17k0;}y}Oq~MnCWF#4dtG5 zu9`Lw#ldtXl3)U>tSOi@Gpr7BqMPD6%*$Gool_Fy~s>%uHoB6oE%I@;>`g##cbgvP3uOZc=STz50E5Hd~=`j0;61V*$ifGle z=d-j1g?^)^+vdT1`yD7Z?idNgeSmt4RE(xTAkeJUy8E46I4Bsszs&_Ou3jAzJf#V{O*!FyzyN=3dGA^WtE(*BU&~ zAe1m(79^C}M5w234rG1=wr=Zt)WG470*UQk4_S;e3QG*ssbhOJ&P49%iv?LJp`JaP zN^8435JDTgSV4j^n$1?a-|3Y64EqTDnroYnJg&IT{=fya*k##|8EqGSXt6=LkC)@W zAHW>u2|ju8K-rx%{S&r*XcrF2ANFhd3G7F*4vIIuzGH-;nuUQ#;3g7Zu8Z#uDAH&Q z0Uu}3gcGp`_C4;x%5Kuc8hGXt(FN^HZiG{RJ2Vdd4fh@U?VWQZk);K_S1hnv|gw=wVuYrOP$&-Z0MhX4qiB|2mU5rlv((H z)qHvAague?%}}TbQe`4nQ-Fa84vUr|H2|F|E)(53A@5j2 zsUb(N_Zikk3OasAUcyTqJF~H4Q|sJ7L6gX&rm9pA1r>9=7d_VjkQr%lydKlBPd;XO zZK!ePX)s@>ihotto<{yccV+h9)w2}-#q6F>L)D(PD1fl=d)}=|$}ptubfn}7%Do9lK<7wxBg-G5-9FvYd=*412&DtX{gJCyFrv!C;Q^i^fS?JtlXBZ+y3= z0x6jZl70njIaZY3>$w1^;+&Yha$lg?T|%LvxNU(K2UQzoR1i+#-a8PF zO#$Z6QaSW>OXepH-jWxLFKTUQpYh!--zk6SlQ80L|A)4kUe|#gw4;L+Ko0g6yCjTf z!L71U&qD|t7R1R;qR`J^ei_@Y2mt651Kp%PPx-0VDNbGWF4P~_6?-8hYwyU@uowZ zyqGt;%Qmg6poJQ2#P(aA3(s~u3lk3fw*XG28!r%mil11Y$aL-&v{GTBO`kQ&K|1`6 zO-bwc5I3mVH5mSbx&;c^B=N&3&3mM@ z7KjUR5Xxq*hV1?Kwn@6;Xnk?YqxTsV8BCXH_3lVUiX9)n(fmOYDEv8AD6ay#O-(1rwJRmxr{D8A+lY|$s&SGF9bU_ugR=_q>!+ig}0sA{Bj6T zEL<7!b!DmOs|^lP%mR0A4CvMlT^xsyz=~&qQ}2fREqr zY*P(6`=sqt+*^?>!0ObLbprVFH zIA`2&k?M55?=aeK0gH7B2$dz5w?P;uOMf_hch^_yhK>JY!UWj6p%&3$e*ns8RbI5` z{ff{q#=|!U644=@M$qP#~sWqssBVy5&gO zC4fH9w4R+ifFtfgBU5GT398z+rzxzn%eua-FeZXKf*AQ^+xb^C+5`?NTX@7mtIDWEQiANa;H z=;+i8T?8+Ynzrk>Y2 zC4Y6uQ=weQtn3lGR^~A0qt7>+zX){j3taZ|mu7$fU?4CK(4$B^_T zelfUcBv~VkdBq{Tysxsm0<7iw^(UYDR!mvn~s1TjpBbw5jP1V3ERgYZ?K#D=iRK}Tc~PW0IpPG zDk2rTEFQ#!2b109Lqwj-lUH?yYt6~=(>jbReFrECqN^0=Dm&uQ(XRF0JI)c`hw#L3 zntC(?=kWg7DYLIpwOYri`1?kI>s+BM?27B?oSt(ZRv-^Pam|nXQd?g7%xaZb4}jg2 zwEl_bDn1GJBxxgCGpiK|rVzR3+s`2SX|SDAXY0R)G|yIwGmxLw@-%IJJ@@wleY4NV zkpI{il>ntG8GyA((%xn)vn_SVJ{5oY<|p5Odl24{YmQ9&3HIwxW@mZf)7RLeouuFp zl$v`$G$Ql>z?Pj&Om%?(eS)|mJS^(bZuDWqG{D4qrUzUkYRqBPFI zN30URP(EO18HBC`roP%G&d*on-0#w5EK-Dp31JbJL+_lc*1nPuGC-Vev;N~)%G!S8 zR-QVpv6_kA?H!jR>W8mEtgABB)^{&$vjW==3y>T|F>sPzm9!`+*5xbCKNPSGqsj4> zJLR-_&GdW9KZ&f9%7%%V$xgH*PtkDhv{DiSp_GC)YP>IfrnLxB@y zCPbpWPPu&F&N~<_{_Jw18|Crgd#gi-R7w0&QDYi(r=?>w5b;_wz)N9C_~f`bIMNzN z^qc9B)2SkqEf<5N-i^TQsl&>u{9yMe+J5TZ!GR-?U9Yn0Q+on23*tqT>6oBuNW;<1}FSs`Lh2agAV*&aNhiZsb5w?!dGaZF!(Q0vMZr;ZUX zg7{C9D$=O`A)wOt>uD|VFJ^6(Yj^F4kRSNa0bG`80+!cCoN!>itwRlw&wMmGw6GUt;i#x~GU^ITv#rg{&Ay^ei#2IUsp+plj3~plN>n$NAI&)1RVoo4DB^&dEg2}vrOUZJTy6iIC%A9DLI01yff^Mw z=gaE_nw7y7!f~4MdBRYH?OIGv(Bs1oDkgp2dw`ue*z?5@jC zKlB)%(WkLi3`4UpzYxV5nvGc{Dj1-9|8Hb;gdicT6us@0;Lk5Pje}Lqd;Ul{wF6^A zbY`*U_DSjm{!?FUhne~O!xeBEcwwGMHlB^m_^m(Ax^v()JmICRW=yRpSSW;Z5!$fs zge20{C7@u!?*_D3JbMR7p7r!@yRB>=m)#0^d`gYpj^5`(*++uSAUX3f%Q+_92hi&~ z62^ZdCL-qq(eS10POqu!l28S(b`lj4|3#*#4-{+c4B8N^-%(SM5Dzos56JC3)RZ5U z4f*!j17?BCm(22RQlN;r!;1%z%IY=xZDF0*hj)fIk{fW+001BY8nHqV%zy7~&N5p7 zXhr*ekg+hxKfV#1=>mQiVE9N6_%I4Mk{FY=(z2|3znZzht6~IcG$q&NTo}=o`U6qE zm|9pn8Q*-b%*d6>ie!@1HTr?fT%=zz78bk20edE)XK?{CrOCuPfufY8X1dC6@WgHE zpbku_^d{q+qFmgzi-U;d)oIQmzVS=Qk2yt7SJZ;+F&&skNv~ZIYF-~K5YXDHlDAJj z$Y%u&JRu;uitw*sHvO%g>J)y>V&>I0VVRhY0Ju~R4T0QiLQlqDewwFKBB|-oE*^ty zj=?`kJ;b@-CP|!a!g^^XsDoRXX(_cJkHr-Y=h`duf{<_5^%PA(>)C-XS!=;pSYIt9$>Z|j%= zTbk;-KWwvTsAk6n^kuQ)98Zppt%TDxLP2?{686IuhjRqW?KTY1AldN@G5}w>YXQ@K z-u?tCD2a&l;R*uNMipRWP$iKhvR#R{2a;kV-G5+g-T)>0j5M#=cr}xQ6d%aosazaP zHVa^#Da6cV(t(2sOs1BZGDEI&v%L-+o3igXB)c*-c;yYmIAH_w4l5@hfO?OYDg8e? z<$jPFLTw0-(Phlqc;Mz)p6q()euwuQ(V{sB_ES?RH)$83zswY!VMvRTVe@7IBw9F6 zXtCW)Meq#?5skvq$pa*|Ql@ zRo77o@0>s)vn9V>ek+I-VH&b$64?0(>%rPk(F>u`&{B#HJ$0Ur8vf>Z7J>2YZ#Q!y zhHlti{AiP#{ulDW!iR)RowE;MKH-6iRr6x{fL*iTSSL~ENZ28yf%ta{sU24Wb4vJ-~czBfTC8Op* z1HmWk-#`xi=%bq0ItJ)K?Ww>&sjV946q+|7M|Q!#4c1D?TE>}CLQLMF;-lKOHj zFtuuZeQlo{{N_Gv!PR%h+oyrq+8TuJ&2FNL1gQ%OL;q&TtPJ6^m*U8d@>b#8IV)hP zlDIF(W0}wQMv)DeUnbzft1TIS(V<|Gzkh_htF;1c*`IV%8#z80vN&8whg~w9hp#h~ zW=!6my=SAQf54P93A^w!PR4wwPFV#LdkSmCA9U=HwEk)kuBc&zYS=CHmXHAMEh5y#uHbtF`fZ z_-L)}=TiX<7-z)H8a#knQ=YI=peuq)2v+p*eIXB;2uv+72Nk}#L4PRQ9SG8Z0tHuR z+;eFG3xs=qHrarNA=8kejk4>?8m0TgbfbujUQyg3ty20sVa`<5^L1iu z-WU-%%Xow!;D3MIs-FrC{2y&q;SzpfTXBpQ^f)G%LW>G|Nd^Ky3i_wDVUBVVr0$Rf zeuIwc*9Fe~%oRKES$W&n0YYk7^z*}k+?+;1r{wRvrO(4-g*`}QBb>6MkRw2SGr|7> zfn+-Q2i7^sJ^0bO#c!2A=iK=C{`{(^KCQJm?k>j2&_&-tD#J9&_;?Cj<8hK$WF$FN z(dM%u$B)#ebWPyToPZ}Dx0f6HBrT&LUJAg7@9!;LEJd}w?}gfzh^4|>MD@LO6dSqz z3dI6a{*`TjJM{p0qqGaw(B#o&c|1YL&z?Iz_au(Yn-sq+KS%l}@kIW@2!=)QDYVH35Vmzd_~Z z^QLp{pGoUT!5;EXB{L>S2il#Q>?P#TmaYa=HmE6wcgY^Q&3x@FTVaZ$%)?QGp`8d3 zw{h{3$urQzsd*q28w>D@tv|AC+) z_SjZ+bso0uR01zT$*t=nNZPzqKL@|7Ln#tvGq+CXpzHG07vpBA&qvltn6ofckC0aj zksB&>sn^^Zk%OFXUEW)n2xgPy-4%vL;s2z$6;A6pRxB!M2n*vs;Aql?JV5OOuDLT@ zBF9JxO|sMPD~D6b0hV|9NLmwkrK4bm7qr7r0u8ITNA$crY(z;i+{ctjP>a=*?gzTf ziFG09b&LO}gsH>dQ~esqS^Sr#NzozgOQhBhZW`}(W+oPNI%~K33@dHDCiGMjX?ovz z=NU8RE8E^;4CCur<+b97eAz#tXxVt%AO<3J9Xc69@}rAhFtwNQk@4{I1WG!8C|1gO z-MdP}cy!%o&C+#rOGi0_$5##;2|g5K`>!3BT+O!PV*D^LMY!Tfc}n#8jgcx1`%rqA z`(-|HJCyk3rp)^{N&{dA4~BaraPg-)J`sfv7XZ_c9}fVyEbj%gsC2H)yVh@C2|0IvMT5-D{Hkh2u_+Ro)9(?kKdL5eNa80MW<6fhCf~NgFAi z2nFHa{e%<)Nz^kQ1kv5I&*l65Nhxr2kA)3SK>5J%-C9D^PXVPj#KXZ{&Xm4}@gV$% zw>PNBeC5TbBj@#0aLhFQX?dpc5w?PE0whAEX-xy|Ub8h3C$ExfuM%+ruh3%=ukcMmp@fFy+VW_BM5Cprp9GIMb`Bq_%I->U;EGftxVMQfr z!3-)}If9tq_mA=|*Q@P5M^$^=f2Jk;KrbWRyufNchy9&GJCeDa!&?3g#sYAZT%S5D z#obiXEs8C7>j@ngZ+TC-z=V3|rKU)l)$D2SBHo$NmIEO>*OddjyeYIjY;=0>)g1Bc<{=+C?{mu$TC}BSF7*WLY=@dje#%x= zgeg(h3r9Q>AC$$H$o?3FM^r$8N40jubX_kNOIGy(%@#PBCB-br<&y5rfEZbFT zPVaAU$0(EA9}ao(yVgM@b0PK2f;qh%xKyE|7s@EZ>|6%>Yi;Vn3vtp0P`mr)!(~@LABB=h2v_k`Tlu7>~1=_>sjCg#+1|_l3Tg5?e zEoUQjKEqLr3A;j^dDu38yKeS<(dw&zgyfY%HovZGCS1BJ{z$ro{96?q_4@DN3Wapl zxb!VD4;KI+`=4SS^K0vut)~BKn+j*JTW9Wz5=dYKkCO3HS(UzxaRYk#mUo<$EZr8F zzo|d16O0Dal@+59wh3O=1!MDIyl_TlC43xGHGRrK=>u`aU_iVqFX+AhoY-nq5uwT% zl08`61M(}5B;`6YCEA)1M!M0{+r^(q_Zs}V|IjeK9&rncLqHLec;ncAV0LS#y^Iso zz3IBFAXKhfJf6~oIu(RJ_V46kB3(BZV zYn;ZR?DeXUY?K0PJGCp&HDoyq782+I4{2;AS%cH9$yPy-?Z082M)<0*EWy>}hGlst zM%gE4w&8LV>B7BK_Z~}bCF)sVXfGOEV;D@^UeOp{hEBe`lI__>T21EYG|2jN#D?8D zkM3QO#_cdC3-sRtlA|WTT7br2!-P3J^)1#XBuK2>B|HPEx)Kf2p1|3LU}4`{dLwoTMVQ@zf9Gx zM2RyfxHYAS-v;qQFLW#i6m5=^XS=*S2L23z_fu{w=aahA-|`D9D$K?b%|Vq&jTYhm zSIKJ)FHqu{Bf&qrf46delkvCKyUnRfOS$zf_hx9`;D(6FfZ`Vt*0hXfyM&wQQWh#l zW!Nt<$UY682XgKBJN6)c<@G2y=>8aW?ViR$MxFigvM;%!!7J#wj6%;T7dP?Jn7)w2 zB}hnDn~)&p`%5n^t38cr?TPUx-7oxA;Wq~7Z^hFU=gi2B%izGBuFT{wJ=42sSISx)#3gy+d`J5#p|kaYpoeOB_^8W`CEKsXq?)cd6-Kq%c(DXEd$^VkD;;ulv{$E)yjW*V(e4!5 zQcJ}+K>WCp<(&R!eh~)+1Lte}=0=f~@ck=>aCV3n9ONX>izRn{rw;<7O7&}}RVR)OnAj#_ldcssCV3k(S%vek>TA%|*mYl4h=}QJ$M$6q zeNmh;1-Ua0qRDVKX@`)Zy7uI!2lYltK5au4vyLGt&$$L~2T;HUv;~J~gFhSn@feCI zEwNVi{ZMDAcg$SBU)dqcqjC&Sp2Sv)!TR}r3&>>mI_A*ZF2ilRs$pEhZDZKWZZnuD zHKKYz{dye%eE){R4kl87)OCJ(D1m?_$r9~T50w86l6vA3_2KyY&USV}zU}J>S)k^` ztStY;ZJ8>2!lp|K1FwCqIP~Km3re(FeiW*7y;&{Y-m~G0i-JsBc|ImJGi_K~beInH zpMYZp*1Bkln$O$pa`Fh9v?;5URqP9)#qlc&SucZ#_3^hnwc(|@;a&y8$SB~!qO-0z zS|RQEGa(7d(AUBUCf~q9ko4i@vn91;mNH76{=_==nZ2EG)bl7EWd%A@r?qcqjV$Tm_BR+V!_J z$V6)uj|saVkZKL_{QiPZ_2)qal#}nazX#a28})Z6o?oY zH#raX#Y%DYl7UB$NVVmNmze;v_ey0Vk2k#FeCgD2G}A@7b~8SrgHdJro0BiC#RNw2G^$}&qq7|wQo0hlY25EV4mD_|`TZ9cRbh3?8<PiT@PIw|!+d&c>@A7?@g^#kpd8m)u5djyUGurd_W-T`gNQsuA;29gY-*i4i82kj_Lh-@ft$qvG&Jc{05c ziX%G4aN$2{$bv8jXCX=|e+hA)hHAxMPx$Glh;Qgj7USH6`lr8?vk)wGmq}k2D@E?} z(2{rEN=WGLo6Mc8s{3a~Wb;KsLA15_;pPdRg1mmQ+YPc$xwkPI-~@W@5MfM@?e+Ay zZV9#5Qn?HCFA$VtyZ3V^RB)4bIzZ*L^`%Y{CMsz$45onLxEwX40wLwwB~7ut7G`It zkFI>!kVN18fy|;s`35Pqmq56qrA_EmLju0!aZ)4@lls4fQRn!Zt}9Zef3<%?KIrSl zBDzDvT>@99PY{K@=ZxHApyyfBoX?osaMUc{C@fO-XL%5dYL6=43Bm2WD#v0CbnAh zm#%!qp`1Z!TeZC|OgSZ1e5E+zvsX5htC81;^u&zOb&fn^*y56Q>swXE60>{#aQglr zY}1b_K0jh7VB)SLgX}pjvE<-@nbcadFSr!l33{k_Xb;=Otb7&`VeRS&SPP4Qz2}(i z`ABsTBCL7I=FWk$`s(PT%^ui*F0Tbj8?Du0rR?vOQD3Wx&fA-1C}|5rDtG(~D2OP* zR?ZT3LrNnNd8U7wt`f$}l1r>>(*6UH@6s&cYm+G|ID#Bzp68c3qa7)oUwyQFK*P>G z!G7c^XHQpdX-l@lOCILgd4j`4?I;D)l7A-+ye=j2iy50+%dkm?W)8fiJLQM*tx0z4 zVdaMDmE6A>e2hsuXPLIPHeaBT*-v^f26-Zi>93jW^yOw&>P4qt?=a3Inz}4-QnshW zbq+v_tk&k{BOiC5=wxFe%6m6)8B9h$f|ANU9yA?i1osR%D+#@htifnEa#WW#uvh?_F-R#RGHvmuJVm(d`#kW` zm3+z2_4j;dWij(TT#$143si6+B_tTo%O7x$TZsM=pV4(Tx&!!o@hk9rusBS@kF3;5zpCOjw%e@JN?48aNRFiGCxX4C z2~wY19s$X;zV#!tspdG|#_lcm^_p-{h(u<(N`_KgvX3crjZ@L`dIR+pA3yCH9Vu_U zl64vie#XQFX5k3||LL%Qt@%Y9(@K!lpr}o;4cH59ZLuD&sW#v{J?XCe@|93#a5M!? zkux1eAY?L4ZT)f}JMbo#(_gkC5CdM6c};yza2QoEu1}eT{;lvMwwL_GdpWmJ{>)9E zWRt(PMS)cqd;wu#1>uNkF#QjqMc`%>xODB|Ox06z!OCi*xYRx3cD>P-jK`h zY}>YN+r~ZCJ+^Jzwr$(CZQEAgzk1Sx_o`mitIi<9B(tP;zP*+ZdkLsOLEKigBHhV8 z9r0DibbMxfJKw=jr?lEnjh-@E!X{!?5ha_8vuGaN{q1;aAKki{kgW=M6J~hspJ8*u zf)gE6H6T>jIxMV3*%2IJemD0zl_Qo6OcS$njEDHm9Bvo?+_NDdk!qpHLAo)pDAvLG zR(ZRAuxvaFZ_@f8bE>J&f8sB?Rt}B2_<|Xmu9}I*KZPHHV%Erbv^*X+sBW9f$*k5% z@Zh$I?EE`WcSBk}BdAyNl10=5Hii5~`{(;1r8=V=GU`}#jl{ScdN6M^tvyL3HkAB{ zstPVccJFeHs>{V<*sHzP!S$(Yt%iF)_mtx!?JKMCBxDdbNt=7b*hb>BQnnHJC=GvX z5y5ESl{OC(>_{fl$WIoO1%5o3_@Jyg?6oBB=cuWTcz+}v4R4@u(&PnM5!8}4HT_wl zH;10>lX`A;-UA~=wIuP(_1QAa%?6fnD7E6mS1S8l7rS(3JHHy{^4oXp2^!r>b`Y!+ zUeKN>{h8``N+^ZIC(A)xE>!>#SD3cfZ{>YAN7-*|?8PnUkq13;!`V!ppa3-4`}p#$dup2XQw~T~GC> zcoFm$2aLzU9RV5idXZziWtY4#`IUtkk-ENvh(c-KAu_4{VY(t98(5a+v;cyzunU3z z71Jx_X)j6qaOV-tB2MP8e02;k138eJx73CZ;1s>vGg$y{cs#9cz(L-oYA!qcFfRUl zeG;JyvtfsqiYh8BQ*Z#$KRc;9Nf4vA!psui@dW}P_pNR=9tA+RKM|{1zj1aT_SH{I zA)^cCe!^n^SGPdbHv2j10^*7-=(OLVBOYptMTBxZ0s!omB}+I?MdTpXYq-uwHm7&c zQmbv|K92Wy)!$Mkp@HZnLHUF!?*s0|?gQq3!|FbbGtHAF$0(#@Y{dNG<@f17KC86y6-IfG_zBrsQy1^lS#wB?&0w#WUw%B7D6WeEuL-8G@JB{ z1RX}01gq>=5gO_^LB|AdvnIq~{UGGD@qjI0cmFwHv?~{F`i&N-bnvn*i4kEO`E%Vb zJMolEEF+^t*CqNbidOZFPt&~b&HmDON8%DjI7Zk?DL?<_M;=U}L# z=^)Ihh%vF3Tv(Mo1q4}eC{Yy6=QnAg)^jFInsc~yEPQYT6Tw6d=^_p7lfv?johHh* zmD=129Q;N?hq(EA6aP!AYC93Sb}Dg4Z`ksU(RnyhyM&AS;yy)9!(xX9fo67&LUbW6 z%(TSWf&<5#`y_NuOYCE7KROn-F(wy0c5{!KlouzyUnrGPq)T8G~tL&bf82=wyLt{CU`tul&Ns^H@rgpE;x zPI7zpoA7NZ9sR{}y%C)Q$WsS;C)>U1?n?}Zc%UP1IB=v0fVPX*^H%>p=5;g}4iWZM zdL-8zwkHH(L7?5BVvPeT8KL-S%mqOefjsF2jtkg4!}=USavx>vBd3<=HsPnI@!>5)f3Ft>1@$I&N3O4 zuyVFlm6@(p;vD6FBR$dKBKV^&1DZI99?CFr5Ds%cis?M_bvx2~Okt|4)7FCR#t1)^z)Y49ghVyaO~fWf+)$?!)) zaNe|kpYsGs{VMWnYP&utyIhm;4g$^jWp35$VDaunPskKoPCt~K6f=Lbf-GhU`&(0g z-)8<0Uw)5hW^v-oZDjHiG}l4I@+PIoYo-@NOk0?1C$_805)=}aQMG3HMX>P|UxK=} zzr?q_b237-7p%mf*aECUJ!3K{y4pMqKSw5RF0CNLHb>#`zc+>2Ln(rhw&Jm-sZlZF zK-~mUDmuRq$%jYWiCH|2>HoQ(y%N1>m@BpH8xcdvf_9y>S_rOyKs63#f)+WC+#i68 zM>dskGIJVvtl--=*cTm^b1WR%dLP{_E9#j>Osp1ZaL9V1;IREjD0gg&1j?z3Y(J$2 z{S=?SNM(0swEdN$ch#!pouypX$O{j9ug=fhq&T7?sgXSu+U_FRKz}FnO%JJOl*&AS z1q81SVu+ZQM@+jCuHt>Jp{5uc1Wft{3G{w%XLo8@+2B?*Yw6hoSJ_o?L$R9 zH!{D|Qb)-esx}x%V_rE=2KwdQS9BH=GN)C@g0dXV0`jzHS==YCJ2V&} zYrdKw7UP={9!XRYv^_`tC9PTJt6vb)u;%^PU%G_&G4r?7AQ+5ynq51s-v=FbGu15U z&dFw&qDMG}AOw)|_?pXYZS2ImY(aib03&pvx7}} zAbB=p>_kw7R13zL&ZYd0gpJ}V?5-|8W1H2*J!*?;(7*gkM-JLr0XGG!HtzCOc9T1FrkQmBDrqj(aE5%-|*p6BI74#s-HI^<=_ zhW&r-+kR|0=dA<@>M2TlQRi8v(Whp|2g;W)9VwZ@t1WC*OXmi}tP#)KW%B_~GU62F%VuG@mvsNY@pr z$1m_X;d`F%D_nj(k`d-KwZ6-_g?jLSnAc3;w=5KJO30vn9MEKhvnuG6X)m|!p_V~E zR$&v!0Aou;qlG7@xXPukCm+a7jkw$r2reoF;Pj9+^<3a7sfz*|5jC;OtJcmc0Z|V2 z&EGc}H{Q2TT>7i+_Y9O(y=)(@z z1x|Me3a>=GQk!8Vd3jL{0N4tgwO%789|_oB{w~(9i$V{I=s%Kswn_^jFRA>RX`ni3 zo$oN1Xzy!pu-*sCBGZUQfU4Wl^YKuC(sUi5N(%cpan0_Yvm4qu+={`%ijE3&D+7@< z%P_FG5n!6}fKIjEs6ND(uxy)|!dZG$k`_$t^9)>3>txa5)Zea1!_>?3hd^iiU$XN@ zJrv_goZ<<2NH!Kk$RE~fGI?2o?@zk*Xc88%=v4%~0zj^q1)RIu{?FUn@bRKuQVW^q>pK>r9Gwte8}skdrD#B19>j!d z?_f$LjQh@{Kf=Fr!672l$v4_&0DsT&qiq(#X_KHx-?~Cv%4L9)uBKLG_<@KBj$Pa2 z4r=UR1$SvPxet|7vKwcF7^)^;6ZERwHYy>(^Jz5d=)tH9sb@q!o@FLJpX`^R+K6 zzftO+S$-iiNHD3?d%OJ%Yq9^1X81w+@<*`xLR{sJDEc(g1?v~jXlz(*;ww{DHA(b7 z{<^FP9{D%aHB+%T$4tmSE(Hpf7rn1kQy3&e3h?ft?tH znSOK}1ls8a*p{ls^W4-ikdr#}>0&E54^oY1U_tjgus2X^VS){fv^YK%vJTL;%_Y}}Hq8s)or&exJ!&1x z%C!95Q}5LlmcjC!F}Q2w6G*FoDeRO;3QznylAVxth6z`AB@|O*dRCi=kna{a4R3#W z0D=05*qvUCP(CEUjoA+`i$h8AN8ve#9w)7DVl&nNKKYx8WV9qnw4Mret;E$kUbY!4 zkI|?8UVEY$r^>nv#gR;JfQEi^Z1e;HQ(GhOB%yZ5N~Y5FogHW@+_D`WYaGXN@;4xa zlY5oNemK{jd68WjOhA`v`?u|I6g;%5MpNQ>qSoCZ#CqaJ+G+D)9DFmFX@&ydF{}%Z z-H0+4dMJ?CA~28}bk}#a896tA#a~C@*Qll?{Mf5Ymn)6;Y8#2N(ziRmx0wzk`W8FN zCe-P9oT&b4lTo~CbicWWR}7%87#!m=!?bB4x~$JlPXW9|xjB_8&O%Z|lVrzgJa6!( zd?;j%K@BYA!BZRerCVX$Is5gSBJXJIj}pZ~Q2X{bM4z9QDr3cgs(*4#5$*U?*8h@G zRFA^9XeQyv#5FR(AlS28Wcscq1+THsoZxUvz)Z`-$R<*JZ2e-t`KDjLI$oDa{2?r6 z3dC7<%}U%3VQu~l22(r(xMoxGrl(3f%0we{wtarQvp)V488Y(w$=b9yB+s) zTHtWoqZ@*}-!fvFs~{so4#tHm{>~2HcC4$iE*bRib-=S-l`JkX5*U_T5VKS*NDcEL zN2JR*RCMfDx3wk|_g9lrAW$?G&@dk9Ps@oE?H#^|=sIc^s72$V7nbl?@Vq@?=Pfe& zw6WXL7vfjb$W$|Y-f#bq?X-1V*4At#)rCHFczrT38hn3w0wY<7bJ>{0_#0~=r{Z8F z)v}eBTuO9@=f3Im=->ef4kt!KzE!p_na*JDQv9f5qr(OrK{v|ssy@BK4INgzJ-w#k zXZw4((@!{GIH!tE2mi~+2mQFD>pI{UJpae_&0#>6<7j2>_{lBj@)&r?%FC*Y^LQ&e zoRx8&hcz@$IOv=-O`HVvPD2M;jtLm#<^Znj!2AS@Y#+tA)jY2G(SV2w#H6W=36`PY z%vmOIdb!JrfawDuoAdRN%ce&b#Z(w^{#S(md9ej~v)nA?)2+FF#~Do%K`n^K=*Tpu z#Z0#6BnnCqC-iUw+vqg@&DG>xAwy9NjgeI2>I-Nfm%Ee*Hi|?7P5nw#dhlepD$WNo za#t%ZSWS>s%s!Gf-6m@YrY7azuhkpj_rE|VQ7qH*bD0nHDcZ(Ltl3g!Dr(OPd!}-M z>Z*mt^l*AM6G|$Qq>K3K#8xue_zy#aSjOWGCH5D6(w9nqilsubd(j=xdQ&4NVPdKP z2?@m;1$vM1vAIz5st-+uFiNZNiJJ!`Psi5j6^3y{cK~1PjQ@orV0jKco^F8A+9vKn z!NTx;uMtFw`?>bYnl-kHcXQKR`{gF?Wh}s=A54`#+9|xKCipi+sHm6e!ml5~lSKE6 zA$5YL*Gy@L>K8FG7Gqj+oQ+H^ff5@2wx1uTGlYDh^LWQB?Q-X0Tn%f_f*(rn%eldK zi!|HM)0Gxk(g=y;7ew)2ayy$=%IIbvzwnIgOC7TNpZ_SfGTdLTiiAQ6;oNKadf@4z zzbmQe)2|@82*!W&2zKmGN-TH6hTQ;RWAOq8QalPcZ<_P2E=R`4OvKjT4~C`i$CnyW z0a8r^y)FxnCJ6mOn^ z&oz$OQh}iG@^QZ*;L$aO$--vf8#3aiWC=`$XCpf8%d5?H$lc$*YE#Ko<0I?VQ^G6C z*XHpAtc}zl&-OVi-3>*qDi_0l`bH0Jp}xc#yB6!vCtW~%sKXu(oKHZjVZH;2(GAIH ze36{TmVC;;(pHNduCW6Y<0^gS$sRf>`$B~H#MZ%Jx8fzsMU6?CxR0Lh={b{2N5#^* zK51}44g9_jtb?s=(3wAz#0s4HO38ZwVOf%HD+p?}|J>tTfp`IEVz>0z~$hdg5r9hp*mf&2yZ_Cbb3yeI)nuB}M4z}9oWSbcS` zot0}h7k>$NYK2NeXD%B7cE*H=w-j5v??=ez+5u7#CyYmS+bm!AAZG@dF8F(8Xrpfx zrwxMXhUkj993Y>{0{jKc{cynwpjkAbV#{yBwj8=2K~8EFb82M~E8OXpD)R+m(gEVP zcR@9$4tpw$!*JR_^Qt$Su;n1Nlt;mauX1GyxJ#3yVbWczkBlOR{@%J9bb$Fcy)$Fb z_s|M+-dl#y_QS*_UWnc0S0zirWUBt8!YvcVk@&-#7uFea+9yjp*<5at0w>~9ZHdkw ze|M|<;%$+EpG^f!<_D}#sw)lrq7fF=dC>-Bq%pc@FzxGbAfe_Xh^i8ZR~k~k+8!|j z;kQzi!z&RV8FCiMQbbH9c*&?4$zGWPC>vRJLWWhz7_7|bwIsET65 zqq~uH^S?}cI4n{mkhnuOz$mL|r*W#$@O``Ufg<40dZ zCmKh|^Vz=6g+*qT)SXBw&sdtP*^ICN<7Fj>>0$iiZgeYbcC&pO8qxgE+l3n1cp1nq z-Cq_^R*jkx6&xp@V+Q6D+kX+oa#zWL2CxA7@%{$mB>moF4(t{=MC5VTJ^!6Cg2CF) znOI41%Rcn_(NegvPJfX=f(A%WiRixgDSi65ZvGl`xSz@IJz70R3F#$j7&y36T;$)|9#ifWM%I%9A9_90rr)(Ga5|O8oiu5 z%f@&J*t^J6-!()k_vuCy5+*Z)&zylR{Z5}OutIb_*HA`{I`Z$9QUmYdHCSt^QpbWo zfqikAHyq7G3k(l3gH1rNWKf=xT*E=xDG>M99(wrF+Nj=SP+`KKkG zrjVyt){n3;6&*jY!E<#9n8-y1*5J#5l1Ceg4V}fjzyUpVw@4||BnxIVa!9d55`p1J zO1~jpmo%KDMNj@-#ZrT6Uq_t1C?%(Ua24mTRJQ6+Z3~c9j3U`585y3zdM8pVq~Ny9 zdOcuM&w3cg$W!J5a-cymZ|{f+*OW-Yq3ey*eJ0rbn-Z@^oJ>f6-Kq60myQ(a;fHp> zZd1vr=~(Vs*&IksABxVH0{=+2;r&XkcQ*6dAg1B zMD7?!3fne)i`-3gSI94aaEn@yo|IVgzkS0rDpy`Lhj<|E^x`05N<(I=eZ}-%BK6k^ z0QM7qGcMFFfmLS*!*|2DdhdfxR19*%Qa_GVO-aV;a3VokyFI=nz(9387X>XqC>^yJ z75c=!D+!=VMXYmTzclQcB%ha!TBi7jjBLZVZtMWuyKP(a_P^K%3+*EI&fek6AF>+& zX1Z}}9E?nh2%JSava?y>ZZe-MvTt4WE!z}Y+#m`2DMprWL7sb= zrBwh{9J`Oy?)LX3f|gcpqu~&ZcNcnYyJj%REtLxO1&W1XVNLdnJc0nRcqgOOA@llD z$`(deVSQ1zMp-N{hV!(ON|3>IZdGO$Jxf22iIM61LLJ};t8Fb})N+6n_ccY9)0rN8 z4&k_aLcm|v)!kRomRAudm5rjr%kIKBKj7M^aq!i({c^XDzl~xUn}_%~U}{&GX?Vq^ z;_UBwhZwCvwdvh&lKPT62>HyYhnhjJ#}?*AJ}J!isFp2hq1BbD;f$bE?!uc%0E)*w zId4_R<&87c8R}n$*%v=Nmb==a zke5UAe{J&CaBy2z)Zyd>?K0Vyrw+4C1$rMhnyNRbMb%iqrgUSeiUNI(%T|9hKq6f% zN$3vQ=x|m}iuBz!t`(C~%NkyFmxhzzjtWB4Z5Z4i#XZ-9K=Y;z@7tGts-ry*(e_?W z{o@6#5c)!h_>+6+n0!$D-t#VRVXyX|7Og#`X;=wiED|17TCa2BOLWhBFPvMuywh$D z0%a5%I5P&-$H7a3?v<{ilqT&d$20TagPsZIl@gI)S-QVYjuIf-m6Gx%`3#HC#(GfP zsY7DC559V-8_7%uGu-biKdYI+{0z8`9;9nD_d{QvC0{yQV=Al*z0dd5Xs*FD;v)q< zJq<9bNP@#xS?TSDXg93*1s<4Wulg7|6XnJ{6`<_ZnLOSwo61%sc)JU8_80Cm@57}) z7hJ3{a@qlks8}4OP>ll&;sNQ(uwcuvqabO8=)WcHAp$VVXyPK3FeIpQw&vR6L?05hU_~w_Mej<=<<9Q1p?J{n-j7~n3F)ApPI7$Tm16+N|FcMB(dgH7Jgax}4KLem z%%+#^(8_{ql$eKi_lcY`d-y7ZX<7CHOJ$~$u+cE0tgC|*4&wqyfbpPT8$H5LeH!+e z{A`wK^TY!QT-GzNzRSGK$fgps_~}|kk3&hfe+cIk`^ZK|enTEE?Y>mYEZ{qYj>w%t z4BNzN>wAjJr?xd-J2#+j47);&e|g~RFI2=yliyBKF0Q7lVYvx_atezPbJ1nDrBOg< zk=F80(LUJFecpG2%J}yVgob*lM6QaloTLVyMy|8-f87avPydKpU%nqJUxOtB{p6Sr zSF1Q;{@FX@Z(Qztps)+NB_hj&4b=XMo|ndzb7?RkVH3;#D=o*sH523R%E0LB%%-Q4 z$}^1_U;ZA$8i3?V%ljOk)0t~klUh|5bRwh5^^O1>lnAyP2R`w|Y?I&fhPkcV$`{M1 z9iFC;$M-c5>J$m#elSSIj5fYTU`nwzBMZ81#iMA)XVV;c&UI;(?HpRPJ9#C{3t6o# zNgRE8ZL}c5koj41dn7}EI|Juml&nn+_pyl@N!aI{r1LMP%Q#&ty-b_32LN?B?& zkL|`-eF1Gxo)__s=j1t^8z5WOm&Q#s(~mL=wgFq~S{K0_86VhMBImx?VtX+m3VEq@ z^Z-}Emvy1gO*$+RQHGH#5vP$ly8Z_vjr$SG{Xh|b(tMnkE*xGt@Ww26yTgt>P^3zy zRIXIy=r7B4Mo2%2iB?8VD)zZmpe*~iX#9^Wmc)d1)j)Ikp~ybuMltla$)PbD#i4?x z5ki>!-t5rm2sfJ$D8%+SESBeJ{B zw#!so9ad9orl*=)l26(%)qxcaeJBZl^*V)d=1)^`NLd&f4=WKUbrh})G z476k*QrITC)s!@sy4t4t$Bp;XqEk9X?RWjoO9e4kx<8rJU(Y7HM`^1bc-MVT5<@VW z@)`xrYb#N|JKY$~elm@gyYk(t!MkP+pWk$92@ljBeqy6m}n57T_STy_NP9KLnBBik7R=;<1fu#FQ!$ePpU+ zs!aYJ9+(xP-oK^xs=>`Y)-bL?p1}MSEkiMPSG9HnLhCvMfYmZqlI{n&aWrakb@r5 zr#oD|fJUe?1SWYVJ&=;X--;TK1B6}$^x*kEPf96Qep)rZqJ`^*w$mK+6()<9!R64b z$0i~w{SUA?u1ae$eQTI>qkFM57k7UEw)J#p)qecreuNB%z++x>AI#YPHqQ^go&#~I zvpyQz?dxxoTUuc`GAM#pUq}yj0e7=s%3o=ZTH~!@K^k&!%5nOoZkRAwr`jGU2vRWu zl6(xZBQ~`ecbnaKG-h0MVWIy^17pJ(6lc}z8`&%+)(^vNS5OqAqQQV~Kw}Vs$~k6D z%=XhZdBm59Fk!tqYv;5#)*y1|H@$rp)krCLQFdSB;1BpM1kP>xtzH|q+}13M&wKqj zq>ndE=&+}~uIZ3}wXPjZ>izf=RcFMY3?sKnu=*hEcKjyXOw{eCH5*#3aDJsXFiqK8 zRdr!nc$LYdZhtSG_D@pTQS0&s?zztqa4ygQq^hwBGOPX>!h-@~1Ekgj(}NVm^MI5% z`rSPou_!c*vq%pl@mMFHg?nZ-tAmg>vB#3#FH6ZmswNBc{*-{A4!M&0)a^NL&w7*+ zpu@Vdf1jxSGbqhxkXQKu)y@h>(<4xHDWi!7t6m^m+FWJ-M5I6?;Mdxl#S&BCf-7Hn zBURk1%<+Y?!N&=*0B`yET25}*eM>&VTdge5t{H*uHdbrij1GzCcF@+qUFIo>ob#IM$zNkT_($kXB^O(ka3rf-rW(8S->1zlir*68fB>Cojt~+f5 zUsyT9F+^4K$Q3e$Lz#PDx_W+U8&`%8(_ac_Sr2wwCM_?VsuFby(hs^`Rpm9N>Za3{ z)x)@A3`ZO+r>^=j4Rer*oOxxEEJ;Ydp7DTk7%`C=ZDwP%{Ot~d2|!ln_|@w4h_`@x zaBkSg&AB)4^V?ClHaX%$oj8WQ)=EE|py{U#tfOu((%?CM1r}m-t6<8aiXU^h%FzpBYF7>j>; zO|v@ZdvELW_Ck?Yy&}+0-|Gy+-320y|YH0dX&DB1`CnXVc6WvhAf2uxxwM zEUladOn;3Yr$N0uH)Ei&c@X@*$!c|p0{qi9iia0p87%^fuDLuK*U0D?f_ysd>@f;E zAfkY}fElLRhqcuqdwCcv34^^Z*fK-OlcXXtBU%iB0cO>rqHwopio6D*qR}^>V}Z$} zj1l8c!sgpt4%)>Azj%}vO`CV2x3F5h6ouuIO}FWAp2p9g{1vwZYj>p5!dJ8B&#-KEwAvWPBZYqq1FxIuqYz-VL-W?yQh8T5$ zv#)&(p>GhffuCe}^#(1ES5l(9;@k)I;H4JIV^pC>1hkkBTA82d&4W#&X1@qz4`0!s zTZ*CQHARtoDQ$szxlS@I#8E1|^1&%jq{Ij1xd^6M+x!vY z(%7hFswxxNfu(KkN4CX>^0^!XkRq}uHv#lKO*#C*&kS{hr~}*kJW#fL<20{v&{*;J z7T}5bwZ=HV_a{tiS9bkLKKeFxY1~p|H^#?6?-MdaJ`U)K;Kn5yN$gvVi%|5$^&wN| zWyR145jqBY4YV*s0w9(lS}Bt8TSxDHN>Jvf22y=y&=dtCdL+xBkX%qql;=`80O_Wf zjJO3PzBY?}Rvd0=(-_!-Ady2(j=`Y1w`ioQ`};N02lz&Q-wd>+E-bXs4|K=8g4RAf zKV!rHDH2f;Bk40?0f$`nWhbJ}Z_Nj+U#Q=Sxmbk|8t4U5gV@Bb7R10$QW#)$BzvJU z8!-0Z>9e%J%W6VX(P;HNn__l59K|k$W&9y>b9~Z0upCINLP80s3V&-at@?o_dKwuv zEmNMaaD{|C`LFh=)sDey<38If7!|v43~QH&EN8)v{?ZJx(kK zL`=?;@uA-lk1r$vx}vi1#&-FE2#z8nbfY`r5wgmB*+8xB@Z!bm;@}r}syg8ztgU61YSe=Fmfn^N&XZU#p z&T@Y?Fm~^+I^pm5b{*IhK!?eaJ^Y5OM*J-0YW`$qXk;1>puP=y&rXF1b09aEe`u|> zo_bEdwHf{wntW8HlIaoW##lP_1A0M!*=?$Wkxz^p%dAVJZPsdSsQxm#Qx;O_7+kml z55P9jN_)^qzB6&o_lZcHyYouf;d8j}^iXVTXSY^U?TZ9K_2ZNWZSk&t^HvTymNCwP zEpARwRt3ZO#Xqu~vC>Sbi*rHJ6yl9>`}ye8gSmt^!x)O|l34i0-nylkOVN@k6CKI~ zH8VEC>p@T>?1-vDwi;KjtVr5OvG%21xA#+xB5d!L-zpDt)+d_k1_(X@Xgd8h=!FN^ z&W`v_wvv$3cO!vL>AJ!vq>$Y9{=ogCDrtbjI%nyt#2)UK2kYd_qxT8s_q2D1#f<*W zIE|WN1{v5Wxqsu>>p}-Jqr`MJ5kP-aPylE6g04K}=xiGj`|n=8HdeXFQ&$s6_!Mrm zfc(C!F~Sv&^n)Rt&hAp6l7hMLd8T(`|4{0MEi>+)O-0fj(Xj=g-1X2|K`q>ZrS0S% zP?Qf>CFV*iO$!&=q|yq4Evw{T8Y4Zb#@#W3(Gs>9LFBr&?Z_(QDXg~8Er!(WhAXY zShKtk9y1kzJflmH`%XykCh5W(`>&;<;l3S+N#H5L_gAuLn!mH<5~O3R#be}RKjhB= z#GmJytkzXu4fr6YM%91UE%-go&xgw)}Q-A&~RrV;H)iFaw?`wy62<#v5gb}Npla-#QT$b#)K!J z$z$W5)7;P$(t)}(>}gqh!8)?nfyAh?#E;{E~6XiZ7J&Qh1$q$*eE ziwn5H-ny~6I%{Ckrp*;(Uam$l9I8lsaIj#%%01U_jhbMtYb`oSCVSjT;%OoSmC6{9 z9tkL-vk`Mzcqb`tL36f%=%QCNr(qw*p+eKCucDQFZ;Dzp_PhB*J>NlCa+5Jh;#MoO z$R;Pqm!1MOwP67>9gjLC6#dgkKh3GpA&kMSg@mOGK#pG}E0crOD^`5UTbut9g)uA| z9YOLz?E~KSe=e-1XiH6I5;5LZfBMJ}pM`GQpEzgk)`RPSr{*0s&6JHZCC}u~LahYX zY_$?;^RV#im?FlVO7+Iz^?zF#-lqh4L&9djT%UFGb$tXUeUwZy60x?4xhaNL_5)G7 zu}C>p3RA$va`Ajb)VgI}pkAhVr3?skz-7{_vQQz}U>EM;xn>&54feTdA(rP3H|Ip)Bk;dX=!Ktnjo z1PAzQG%w$$l3v=xAL^nGeZ&`U5|q|=!npV!sMOmPlq1BdxV@r7=V(*c1cWU*ge<>);yd?PG*S%V>5 zMI_7tbGwTTiS5eN84S2sllsoly|{kNjwFXc#jn+KL;!1;cEeH}Q$$+&n5=@w85tIA z^}k-5T|-FP`_dVXMBeKDW>AkY+BJR2Vf?r@3KB?>5}UnL(aN zS8qP%CyJMAxH>9!6U4QD^VmyM#4Kx1ieBoRbinXjzo3nl`vn)D05(NhG$Rnk*K>c# z(J03bJ^gY*(COf+`Y5RDvS)JGQ0JnFFoNeL6oHn`i_f&QFqjlh4XFE+TG?t8kCRwV znp7iTUx!@6Cs7|zlW+_f$qL+#k4~acdEs=UuNH&?;*1j823lTT zFsP3+W{6nnK;R|R3O0&J-=^~EaxZ;;Tme8@d^+1lGjK)^nS5z^sKSXUdM%dS0*vPN z*357U%g+;8a(${yC{5qn49NLG#_<^`B>sd;Ui&%(JY!$oQcn{(R|qLvr1TAz_%MN7;9lv>jELcjNcQU&yS?t?dI&A#0*b?pQdd0y@uYbT{&9c0 zGuC)J^j9p|mDx`7{4CSF^mgj)(~K7do&*L6DA%~G)#!N*4~n_2KSy#me~8@rZ4PPN zqrB!!4oCIGUo$gpnKwhBm>Q%CkrhBiABr4#I|;N>0Aqdz35kpKwX&|0F-{a@-dV%8 zGE1^uxRI+lEFd6eA7gZ%)^z%dH=FL!VCq_j7kUCp!uNLy=-LM*2i=M250cQg0l;eK z6wp5xt!E0xaOqd8gh*n^;4(5@RFSEuOE%(T&?%&=)c&;`N+WedKW`mvLt+ z*Ey7NR?@P4Gr{f)4UcDG5`h6G4%=6#rkRdFk@M$ex8w@XI<;lVsYmf;FySi$TTbBZ zhXa_A-XPd~+r>|-r?Fr5s$3-Ipt!wjGhSZY`&^4zP7f^DO~=dUrFV5jotNjMsrC6k z{Vqu3>kTn4{yh#IdK45adsnjkxXQ+Ev7M+BRMU)iwd#(<&95mxZ0eFdL?bVPrAoF) z_Iyni;(c-BzJi166hb=O3isAy* z@(V5AMJ;gF_DdOC$lSrZt@#?6kMO6gqSDvYD%a59 z^PA%n3k$Fr76O8FZ%H2!8sWBaz|?QifQ+ZKwtT72JFEk)HDRm_G;hjTHsImL)q=syTKp9 z0NCvRExr^<=yN=mCwpxahhVa2W{E>3f9rltxl1sgv4KTV?-x3AM!ebFBkqOOgT3A9l6rKJhDAgu;QKi z4LiECPsQ2(XSIri4!xwygjH#X%p@nd z+d+-AaRJ_lm8tm0!R$*I(|to}iXXG+@O&FDE+$b`-gfsag-e$4edZab6niRq+#4zy zCjTD=#R;zfk>_se{;WthO?tz+urG~;S?U@AKcy&L}8AJj;zqCr~%9wUqC_cm&xck0zF_PUStRBl`TiPe3{G_9{SxqExiA9 zE8^z1Go8yRXF9yrD{}Ye@N+4FX_7VL^GlnBP2SvVh%e#(H9C<=ic7% z7ly(ZQ18!rD#?(g4H?pcLl*Z5f%QVBQ&4kF#p+t;S*Hd#-p>=Dj0t>XdcS$bsXER> zhgMe$2lwYF!1@j2d<_kaDEl7bt8p+r@~WT9+trJtwhJvRDuZmAMuqj2V}!!>@`cR9 z&P>LYsipC6A17ePZHgKr8vCFrHh{#vML7`$;UY|@8s+E8c)t~FG-%8gvQ+;}Rz-us zEmu;(OpIge!v1+^l(BXKDWRppKP1cV0~Z{(O=gn#!o3BL_sGhE10!`Qo(=`{c~S~- z)XL*Qx;Y#|M1HUh?Y)ETQ7=HPUoX)l$K7CX(#bGDM%k^Yscw)Xkj30 zA9jY!#D+IFVc=TBn@!=C{8#7IYe&puCWfHz`30=$7!Y$bi*3+G;;IA3qz~iJ^e6rP z`z`BVy(BU3M1n;VLU2K|9>sevmowYsUC+ zDn%qD?+O|Lg@+Szans8$VoI!qI?<@CF?wOF7TnwMor0qa^Tek(P$S#DT{j8i%MC#Xa+#kzn>WjQE5Cz^b|4=?^}es6k*l?Z zW@k)^m$!s$_+fIJb$?B}vEO!A0HUI?U(P6TzeOJ~B0gK)2BOA$pLOW$B^4dN&4W9& zbn4n8uz?d1SeSh=!I+E@G5tV#(CaxzA^ppznGm^0VdjlR0zlYDe!RNzA*$AHSyL~Z z2Ly86^Ms4!6@zgZQAzRWLiK03_a8IZ>`Um%I7qi?;gukt9T4@e92JqSO1nQVKDVY} zJ3}CeK5YA*-|oQ^W9yMHj*_AW{?E!pbM+$Me3Fbrt(+}+w+k}nR8}}TvCM+iXs9q_ zMP}4MOe0XI5dKZ=8B?Mhmm#dxm2A6b)-aZS5k_TgCvJ(`${}UXq9{i`An8-#?N#}Y zY>Bq&{u+VMO6g<+f>ZJ8)PFJTBuAP^G=PApBn zMH!}zYekatM#g&S?cf;9KV{&VH2{*+si|yfHF(v`i2YI)#$p}KXpM?{&t!6eD{7!8 z9Vn^SZ;NEseH-7p4mK^WOs-r#Sb2BM3fylHWtWW&r?pW>aiNJ+wRJ7fPB(4nfWqKi5;5qY5gA{5g~6cyTN+T}ijD zpHQ0`=Bm)cIf$?ZBTXikIBkqt0TVp875)X8^u?7`ExGs^!Yha7E#$Y^n7*M4WQNw= zUxV1{T)Qux@kOthvZ;Ck&UFc{W1g=Ae5r}RJrVvsrO}t~=tS=gXE?)Xhduq#!&jfZ z=mlwwM*c|FutJ5f$1=rzU@im(8ai?>g8#v^e;L5*b{fM9WJWE@*6 zey*JSS@kI{2~j55!u)ry=Ye-@oCDA7Qn}GFlo|sQO?}yQ|HY8VpCIEd+wVxfg}DMw zO;8Yi_$*RSu|}!Vh@BH}vL=~`0|s(gg-C*&r5!aT;Y(;tfzh&f{|7?jg?>ZK0J%8l zcGfU#;e&c)c{6au7;`6WcX1YAlSe9LGrcGR5q-wwc(a89$3Ev)`o>*jks%(h&{-&R za%gi18fq?eIcF+7r4QQyPPnxY4bsN3q>LTg$SNfzsbY6wkg+ z+4AcMrWPvaXt}`)$bn`AHgjEkW8-)j5AnsS2vV#Mj)j{5hCk-{7;db zxH~>?%L%24A?H}-GQ;${YI#z)!di2?7+Zdz25lOqZgf4ami3o2+)$dL!_X5!;H@Jl z_;b&gd>-@;iD(vBGU(8l$roUW#CtCvu-*qZ0pIe$5oX%fhkKR7#}aLwV0>JZM6mkh*Z zL?y)|^VgUQC~qCJa`Wx`7xDYH^@ydTC9fpXGDPEsE37KDm#dY!y1ffhb6Ey|xxIUj zI~;i~+>|+tjyg~@`MM#pDnDcL&WBFwyhwElvv1@N2FE=xmGf&4-Tx5%vWKu-T2Ilw z{E|l@nXuhfmvfa{293&E4FJ!G1K)$ycI)t3Z2Y7h{j%i3d1nc<&9b+F@cFtoeskJT zm^jAtp_zeAWFBnbkW`Li<0efg{fi@B2!JVM*23H9rtm!#Uxac1WTD}eW`RTox>TUK zVEDIHT2+q^RAP|VGTuu1d~eEK(Jb%(rBA!#xi~R6JFZYe(8_cyu_@bjnoO15yC5Mh zxfngaGzIUe`FxF5nym5o+sA>+=|R0HW0A@!X@a)*F!l?l=Ol!6lQWs0Enql}q}63~yv+L;!|@d= zFPm@fO$8P%^ySYecHcMOI2UW~t*j#m=1Ix>&DUWm$YpFq>uL3t^$y)~RIUAZ&XV(C z>%u97wNN?r>I!}{;&i0d3z$Bggk?4|{WHh@Q%AStVkEi zW6LCqr2AaTJ3Qc!WcMg`a5899;R#S&f}Qm7b?Tv_l4dH!DX8xhlY3k~H&kzirp5W& zEWhwm;H}Ys4Lwe_lyq(fTZG%}t0)sm^^x&x69of}9DkBW0BK4!@E)ddC};%)Fzyy1 zY9SEKmTnLoT{d|A5#(?~_nV14ZoHF%7Ae4o*p3#pIYB8GRz6MR+ZYqmz7vxJOnUM} zAcbVz$EAc<*9X6j9omrba2m0k&X)pp;3r4P+-7X+j}@!fsBqv3A8_*L2~VT?01DLiC}Sa~sEww$+z=Q)eV3NjSRhNEiiQNh~dF#6)9n z!%cd0o;x?5S%v7iIK$Oz(LNpZjr-pXL#~Qy5udbvuSYeHTOW)kBR= zdf0M}MxQ&eQuNUZcX$d`1nlO7j~fU2=SMsvg?VzpB*JgOdv{dM&%*IyfggohuWp@$ z=cVNa90PCs)f1tSLc!yIHFg$JaWK)g z#vu@B+#$GYaBm>EL*v>=ls&!S?@!`{ws!+;fPbJTcC*fK;>6 z)#laTK-jA$GsJPI7rY;DbJE@?KklRlkB}!LRWT@;#TSc`uBb z{lgniZtH@RFTw9Cn-6x9RV%bBT6Srt5VVDpXZs>$uI3V^66`wd3~a`#M>g{iW?$oA z)w0o7C)(DhtaZb%OXK4}22gd59Bb8$*ovpad=QBlwH8H(1a_+Ti|~`%3E`xzE{(U$ zy|xgf^o8&x(&XnTndRo?{&%k=5|*fxd93%ED_Luy(Y}JxSsP2_SW!vN6DBiZ2@-iU zqgoZf0=p=D^H1*TG>qp(l~598an0E|qhte9EvhI;Ec@m$H{I4UKgui7T zE|w%l#$}3LJiAE-$hS4C(?Ep{&}1&yPq&LbS1>+#Szn0J+CA?J(>Cg}b`zg8CrnnZ zP9yUjlaYy`4IvyH2SqnmN*P>pVz0Hu)Wjq((XxI~xMzu}A6NSw4H6Gv9WmbnU4$HI zeB#%kLrsLq?j#WJx#;}14fzV1xD0fu=gNfV&mKW@&Q-fOhIbPzj+)_6GLv2R#!@bl zh8=Qto59>`cMG+WVLZQ!nZ;8>{DMYE#}}XrW3Ea>7-{GwL>>=RsoVV?AQs^ker5c7 z8p|Y@F37`a8qVMovGTkRkXm)U)W*D}>B&U8Vg1D-Yn#|VXadU~zOj6Y@w(UsV$Km* zes_@RG=F|JLV{!@U}IKtFWie=^YS3$Bq0b;Rg-Pov!8aOMF1kq>$HU;PWwtX^` zDZ)LS3c3jicE+r0!%JD00ixiOqS3rPe!sR6F0whOb#=54ZiL$Jkri97 zdgmKxs_s5?Z|rkO6P-$S2fcBeq$6EsGM&A6L`tsE%lD5qS2F{REk>0CS29(?T!aIB zU*k_GGqyQ-&I=j00p!zt?6Jqbb)H9BF~+g!3ebo$^iIh0RetcE91zYNRn zWM)que{#|W4JT!IgNyDH3Iq$z!eex>nKDxln4Y4mBph~7iTxC$)}SmJF5uk?eR%c>~Hl;liKj=Kr0Io9$EQO-PgYoEFJ*@3|JUG->9H&wQQb-*g3==fTJ3q5*U7a z@YZFZ2}VkcAN7jc3eZY{IqVv{ySu^{v86Lx2`)l%&k}Gg+dy=zz$(Zs%&lNjADWG5L^+hdvIHHD8RziBSFr2 z%|FtFP3%ds%a+L=^zCCINM`+)3i;?maU`UzYx|2mS`90UO2&`pP}Ktq(2zOVt1>%z*2air$O&LiilK{AcHC^?P~uz!kCLU=+T{ z68Xw&8t0)9_>1-AArfj4a=ug81zdO!< zjPHH1_pH(yVBnx&2<>S!H}R}@l91To7kU{5C1ki1sZ*^wdI7lAQ^gihMSCUZLKIw^ zVkA<)iQwB}`SkDjK;lb{Uc)X%2XPZ%LTDzbKVF=96VU zMkYMBkujNsx^rkp9+QLLVJSP;H)|+a2J3eYs#-XU05RjTtnCB%m^*24%)+d79q?Gb zaPqSK!bQwH_zkK*d<1{vCxI-#swbcPIH8Myb6hXRmJNOkq2bwXKm6IS8!QA9SlP3M zr4L4{t0wQOoyvJ7Ry5IMdP}PJ|07-&glvzI{h z>Pf$kmx1i#Vr>_>pD$HO6oq-)A8Wo*cRafoR^MhBJzYq29t*SiT8ZP-7w?ejm+ZFg ztmP-7eulZy9})TVr|MUwaZlB2I-q@>!jxSe3v`@dpz`nhAkiH@vDb4>mWY81{3`Zr zO$NDkM#k9X3!SHxUTbseQxj~a9cvh*u3gdj9k?cGlLf`SH5gg5Ik`7#yo=djj;Cc0r8o;7R4;V;j@Z-k9V5aCG^Bpe+ z%t!E(t6<)9$OYI+o`CAWt}J3U3}_rfjQcq}Oj{_c$5g)=&xV2>hI{u=^%hsz>ZqZt zyO=RTwfqW1PF%@qrKCdZf%a65e13g-()Mtj69edZaHOfmAg@EEm12@*=>5mSR<+0Bd*3h_UNF49>=>1buMORczm& zSfXh4+y-#Vi|#jNOJ!itZ+lXplWp_U*4|7YK{h=!N=tYY8~mO2Oq`d0w7~cz=qio; z)(*(t!YksLVi+W3q3>Iz;|-JFOzztX1W76ykTFHb^KAP9xNeG+xmM#PRUYI7`OcP1 z{v6y3{eDDhtJ?~3>!*vO*W#^2BwZ{?zkXm8RgtrbNi5_Q6Y}*A2$(#Qn|`74q=mf# zJ1b)Zh$xj*a_v9+!bQ0|q0wUF6sLf!IZWWmV~nlK{a4EdBRkba)9h&Xve&|#g!FUo zP`CKDOMVMH-`JS4@}d=)vG9zyM~Gk50;+FAyh7iL9EpgteBt+ zf496?j7BRbP15^j)FjtAm`@tYbXLVqUCaC8I;heX5^ImbAS7QC>tqzytJU@I@hwC?(h;3`y=5X&bD*gPwDV)yB8F%oZ6F$2oprGOdx~!7h!np zbwTi{frRB-$JVEW$P<9$=7Shz1qT_hnNB`o|kCJvYKl7PiK+M_#6;P{} z;_Z_=8MCHfJubBTO~m4^nB^?0YZZr5(U;eaf~mQWL|cwC$?dw#>nD$r-fmX)7nack z<~}CuL|}&s4zjB_ko6{hLo(8qCVr`+=!miU*w#30JZ2&ot<&d|ry4G`?}vjV1IZOE zQUh2CCeJZ4~S5Aoo@ayAv=RP4@11))3mxgE52IY;KkU-=V!Sf+4TaTo-5N`+eHe`o*QacfA< zC+s_U>?Ljsq zgcS0tyCkr<3uKsD_-N0k4a?yY!)Itfd{U$q_>mxlz(@vGS=zdMORZHnubloC!S+hU zu~7>v!v2=t?9o?#vnLKQ;txnyc=#ZnII$zz3eea2sr?7ci?TJpXz%p^P;PeK&(rAX zcY*S^jIt>HAQE7D{E40SCyyBM$31Rd#8yi* z7}2wut*z3O9U&cVigF20K^MHi)WO3}1#R|e$Bs|PLWuyK-)$Caq|sB_d^vDDPzZXdX7wFOZ&?kEtxDP(#hgT=_(#G?MCK*a-TK|(PiI{k z2zzxIgqwmB%4uoCULa!~osIi=it>e$6*e!<2N~*%)Q54RpM5?)Fs(98vkJir_0ps4JU%U{fRyI<3>TIL$33r-~&o9CX z(8(f$V=fKL0u@@euP97-mF0~-)^JM9$rYbDg;8)0(#9}P^D=jJy$^JKU}06M@2y^g zy`#&PcJRNi8juNLkL%?;*pN$32W0M`%xlHxV<8nPl6KFMsL{6ln0t*9u$dk=&m#rn zK9^sZ3HZhp&k&uT@%RWuA>_k1)W5Jogq09RSHlrO6K?nk>ztULRQ}sL$|rx;3F4|R zpv{b5+U2USgzwsK7Poc37Tr{qITNBx>Csi+!6N%Ori3=en7Y^{iQb|1c}9K?u3_p? zFd*moTL%~qneH5Vt|vIW#XRax{$h)(fIT{rx_7g*GtiX%JmU)%Nss-rDT0nvq?UjF z=}-U0$wG?5p5%!=Qmbr(*I|}PW18ZH40ikX3y*-QoJ9rpT!?`ry8zmt~@I@0OExh=b;^l90pi5|OoT0$BgxTj~w*Ot-K3 z@me^}#i&5~chlMD#WK`c@zS{@R!u!Kk@zEHfOl3M0hI0h5q@L*(sgRiT70}Is;wh3 z-TEULHkjmGCg^Xw@}07u>WiYj`6-$TXutovaJjD#NI(S_r^07tR!es_0@y^#WmxP- ziNHIG^LkZHp^46p^?s%LA=C~O7Gp(b zo+pA@%G&1A!$*|y0J8dTBMFCn+!vs4#6)(Px+t`kDH|>`@M$C`1n*dBAZX-a)UxPh z)K<>IKA+<_Q9cK21F6U(15!orTt)eZfT@3{k5kZVgV?Uv^n2@G9@|gtOuVFZx+{8_ z=-zk2Gx&*~zwGwj)5=&hEG^`&n#S_EIu6b!i*Jh=qm}h`@%o{#;=JR1VtzADfL=vS zJ!(_S(AFp@u_)Eny(S~~m8=ui=Omy5zsD;j_oCT9k_?0cXotFeib`}2E zDjvO!iA0|{?|W^zW`WG5aaW^06ENx{e{P5MStSESmFG$IvYv4$gjih6J~4*dhrVb$ zaPFoxj^7rNoZ{)CbsQDM99`gzV=PD>`dyiEMN8zN^Rn|~uwsxj{6ZU5?ZLURWl8L68vgr~dTXZbs9WCbhVVpRSgUcLwbzOe@e5V_10CSrZ9a@S|nR zk33mGSdfnq$2G_ctG#RB5i4lAz7itGSuP<i$C|0IcjXmHIg|I+HMjqV zM!w9jx4njiMdb?XxBnxFHGNB9F1zvyPenTPO(VDedje)sylLfXS;iL30_W9|g7A5Y zRP0U?8aeA1sL2mU@1RpzsoEqT93~o09rvEsR|5G?1E2+z_W%r5{v&bK(p=WY* zNJy;Oy^nC*YlVV0UyOSGzwCcqQ63mcUYAswUlsa-J~eT_9z(Z?!b<#%>A+-=pRgJ> z-E=xT-RJaQJ36l5A1V5u^%YVfmth63e-bgK|ExEij=xJbl8|L+LW^6Y{bxNDPNWU_ KKThYrP5nP?wTGVo literal 0 HcmV?d00001 diff --git a/products/messaging/get-started.md b/products/messaging/get-started.md index 30404ce4c..165ab4c05 100644 --- a/products/messaging/get-started.md +++ b/products/messaging/get-started.md @@ -1 +1,149 @@ -TODO \ No newline at end of file +--- +title: Get Started with Messaging +description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. +categories: Messaging, Transfer +--- + +# Get Started with Messaging + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} + +## Introduction + +Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key +- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} +- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} +- Wallet private key + +## Install and Set Up Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git + cd demo-wormhole-messaging + ``` + +2. Use the following commands to install Foundry and project dependencies: + + ```bash + npm install + ``` + +3. Use Foundry's Forge to compile the contracts in the repository: + + ```bash + forge build + ``` + + You will see terminal output similar to the following, confirming the contracts were compiled successfully: + + --8<-- "code/products/messaging/get-started/terminal-output-01.html" + +4. Run tests to ensure everything is functioning correctly before deployment: + + ```bash + forge test + ``` + + You will see passing results for all test cases in the terminal output: + + --8<-- "code/products/messaging/get-started/terminal-output-02.html" + +## Prepare for Contract Deployment + +This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: + +- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji +- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores + +The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. + +### Encrypt Private Key + +Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. + +1. Create a Foundry keystore to encrypt your wallet private key using the following command: + + ```bash + cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY + ``` + +2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: + + ```bash + Enter password: INSERT_DECRYPTION_PASSWORD + ``` + +3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required + +## Deploy Sender Contract + +Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:sender + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + + --8<-- "code/products/messaging/get-started/terminal-output-03.html" + + The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. + +## Deploy Receiver Contract + +Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:receiver + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + + --8<-- "code/products/messaging/get-started/terminal-output-04.html" + + - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file + - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji + +## Send Your First Message + +Follow these steps to use your deployed contracts and send your first message: + +1. Run the `sendMessage.ts` script using the following command: + + ```bash + npm run send:message + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + + --8<-- "code/products/messaging/get-started/terminal-output-05.html" + +4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: + + ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) + +Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. + +## Next Steps + + + From 2d9d11182ca25d7111eaf6c0cfa8f49666283454 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Mon, 19 May 2025 15:37:18 +0200 Subject: [PATCH 13/55] Queries - Overview (#388) * page structure * page content * content * Queries overview content * add get started to timeline * Update products/queries/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/queries/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * ccq server mention --------- Co-authored-by: Ilaria Enache Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> --- .../products/queries/queries-timeline.json | 22 ++++++ .../queries/overview/overview-1.webp | Bin products/queries/guides/.pages | 2 +- products/queries/guides/submit-response.md | 1 + products/queries/overview.md | 69 +++++++++++++++++- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 .snippets/text/products/queries/queries-timeline.json rename images/{build => products}/queries/overview/overview-1.webp (100%) diff --git a/.snippets/text/products/queries/queries-timeline.json b/.snippets/text/products/queries/queries-timeline.json new file mode 100644 index 000000000..dc42275ae --- /dev/null +++ b/.snippets/text/products/queries/queries-timeline.json @@ -0,0 +1,22 @@ +[ + { + "title": "[Get Started with Queries](/docs/products/queries/get-started/)", + "content": "Install the SDK, request an API key, and run your first verifiable query.", + "icon": ":fontawesome-solid-1:" + }, + { + "title": "[Construct a Query](/docs/products/queries/guides/construct-a-query)", + "content": "Set up the query configuration.", + "icon": ":fontawesome-solid-2:" + }, + { + "title": "[Make a Query Request](/docs/products/queries/guides/query-request)", + "content": "Send your query to the Query Server using HTTPS.", + "icon": ":fontawesome-solid-3:" + }, + { + "title": "[Submit a Query Response](/docs/products/queries/guides/submit-response)", + "content": "Post the Guardian-signed VAA to your smart contract.", + "icon": ":fontawesome-solid-4:" + } +] diff --git a/images/build/queries/overview/overview-1.webp b/images/products/queries/overview/overview-1.webp similarity index 100% rename from images/build/queries/overview/overview-1.webp rename to images/products/queries/overview/overview-1.webp diff --git a/products/queries/guides/.pages b/products/queries/guides/.pages index 30fd27cb3..de751d6ae 100644 --- a/products/queries/guides/.pages +++ b/products/queries/guides/.pages @@ -4,4 +4,4 @@ nav: - 'Mock a Query': mock-a-query.md - 'Make a Query Request': query-request.md - 'Verify a Query Response': verify-response.md -- 'Submit a Query Response': submit-a-query-response.md +- 'Submit a Query Response': submit-response.md diff --git a/products/queries/guides/submit-response.md b/products/queries/guides/submit-response.md index e69de29bb..30404ce4c 100644 --- a/products/queries/guides/submit-response.md +++ b/products/queries/guides/submit-response.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/products/queries/overview.md b/products/queries/overview.md index 30404ce4c..1b0e41c79 100644 --- a/products/queries/overview.md +++ b/products/queries/overview.md @@ -1 +1,68 @@ -TODO \ No newline at end of file +--- +title: Queries Overview +description: Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. +categories: Queries +--- + +# Queries Overview + +Queries provide on-demand access to Guardian-attested on-chain data. They allow smart contracts to fetch real-time, verifiable data from across the multichain ecosystem, such as prices, rates, and liquidity. + +## Key Features + +- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time +- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation +- **Cross-chain ready** – request data on one chain, use it on another +- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts +- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} + +## How It Works + +A query request follows a simple but robust lifecycle. The off-chain service responsible for handling requests is called the CCQ Server (Cross-Chain Query Server), also referred to as the Query Server throughout this documentation. + +1. An off-chain app sends a query to the CCQ Server via HTTPS +2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} +3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} independently fetch the data, verify it, and sign the result +4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response +5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data + +The CCQ Server is permissioned but trustless. Most queries resolve in under one second, and Guardians retry failed requests for up to one minute. Up to 255 queries can be batched together to optimize performance, supporting efficient multichain workflows. + +![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp) + +## Use Cases + +Queries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + +- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution + - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + +- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + +- **Multichain Prediction Markets** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds + - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + +## Next Steps + +Follow these steps to get started with Queries: + +[timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] From 46a0fe9d7a9d95d589b1e7f58f1c67a69ed6e6a5 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Mon, 19 May 2025 16:51:38 +0200 Subject: [PATCH 14/55] Messaging - Overview (#387) * Messaging verview * use cases * use cases * use cases * Update products/messaging/overview.md Co-authored-by: Martin Hofmann * meta description * Update products/messaging/overview.md Co-authored-by: Erin Shaben * Update products/messaging/overview.md Co-authored-by: Erin Shaben * Update products/messaging/overview.md Co-authored-by: Erin Shaben * Update products/messaging/overview.md Co-authored-by: Erin Shaben * feedback * timelines * typo fix * Remove .DS_Store from tracking * Update products/messaging/overview.md Co-authored-by: Erin Shaben * timeline * Update products/messaging/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/messaging/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/messaging/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/messaging/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/messaging/overview.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * next steps * turn timeline into list * Update products/messaging/overview.md Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria Enache Co-authored-by: Martin Hofmann Co-authored-by: Erin Shaben Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> --- .DS_Store | Bin 6148 -> 0 bytes .../core-messaging-timeline.json | 13 ++-- .../wormhole-relayers/relayer-1.webp | Bin products/messaging/overview.md | 65 +++++++++++++++++- 4 files changed, 73 insertions(+), 5 deletions(-) delete mode 100644 .DS_Store rename images/products/messaging/{ => guides}/wormhole-relayers/relayer-1.webp (100%) diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 110c65359f5510fb8be3cc9561fcd92509f37962..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKL2uJA6n^g7HDwy=0i<1!B5|EYH_)VsOV_oBNx)%2Z~#=AC5(tHo|% z|G;11$}i!+aDwkWds5mCP6#37C)uB4f6spY;@B|}sa_fF619oQLt?DoKz5CBJEs+^ z*_sWYl0Ks2RG)^a4p+FY!YSYs`1cgxZ?{1qm6T9Q)$fvI#}m4qBDvq zuYBvw{qj3*ILR;UzVJ1?NRzzibiS$DTD`H}^qSs=_bPa+CqXeP%Dgukzu>2*TBqSv zc@#cN;>oam>quwCD9PfnI3!UF%FE|T7U@Y(msymHZ(tg{me(4#x2Ds*gZ*v)L1%Zi z?N1N(Iw;@YpUqm{?Ys9Lo($im=b8Q}GbDwbOl;HQ6?{TrVg8rFI7@YQhI;n#piM>* zlzC4(P-#g^bqAcPmN$j}hQ`n{rvg~gDX>H-Ues26KUdyE1Mez^- Date: Mon, 19 May 2025 17:53:44 +0200 Subject: [PATCH 15/55] Multigov - Overview (#397) * first draft multigov get started * grammarly check * add metadate description * add tally links * link to next sections * update title and metadata * Apply suggestions from code review Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * reorg * rewording * rewording * multigov overview page * multigov overview page * multigov overview page * multigov timeline * small fix * Update .snippets/text/products/multigov/multigov-timeline.json Co-authored-by: Erin Shaben * Apply feedback * move diagram to architecture page * update timeline * Apply suggestions from code review Co-authored-by: Erin Shaben --------- Co-authored-by: martin0995 Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- .../products/multigov/multigov-timeline.json | 17 ++++++ products/multigov/concepts/architecture.md | 8 ++- products/multigov/overview.md | 57 ++++++++++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 .snippets/text/products/multigov/multigov-timeline.json diff --git a/.snippets/text/products/multigov/multigov-timeline.json b/.snippets/text/products/multigov/multigov-timeline.json new file mode 100644 index 000000000..95fa00240 --- /dev/null +++ b/.snippets/text/products/multigov/multigov-timeline.json @@ -0,0 +1,17 @@ +[ + { + "title": "[Submit an Integration Request with Tally](https://www.tally.xyz/get-started)", + "content": "Apply for MultiGov access by submitting your request to Tally.", + "icon": ":fontawesome-solid-1:" + }, + { + "title": "Deploy MultiGov to the Hub and Spoke Chains of Your Choice", + "content": "**→** [Deploy to EVM chains](/docs/products/multigov/guides/deploy-to-evm/) \n**→** [Deploy to Solana](/docs/products/multigov/guides/deploy-to-solana/)", + "icon": ":fontawesome-solid-2:" + }, + { + "title": "[Create a Treasury Management Proposal](/docs/products/multigov/tutorials/treasury-proposal/)", + "content": "Walk through a real example of creating and executing a cross-chain proposal.", + "icon": ":fontawesome-solid-check:" + } +] diff --git a/products/multigov/concepts/architecture.md b/products/multigov/concepts/architecture.md index 587f87412..fdbbbc302 100644 --- a/products/multigov/concepts/architecture.md +++ b/products/multigov/concepts/architecture.md @@ -6,7 +6,13 @@ categories: MultiGov # MultiGov Architecture -MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. +MultiGov uses a hub-and-spoke architecture to coordinate governance across multiple blockchains. The hub chain is the central controller that handles proposal creation, vote aggregation, and execution. Spoke chains allow token holders to vote locally and can also execute proposal outcomes specific to their network. + +Wormhole’s multichain messaging infrastructure connects the hub and spokes, enabling secure and efficient chain communication. This design allows DAOs to operate seamlessly across ecosystems while maintaining a unified governance process. + +The diagram below illustrates this high-level architecture. + +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) ## Key Components diff --git a/products/multigov/overview.md b/products/multigov/overview.md index 30404ce4c..767376b66 100644 --- a/products/multigov/overview.md +++ b/products/multigov/overview.md @@ -1 +1,56 @@ -TODO \ No newline at end of file +--- +title: MultiGov Overview +description: Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. +categories: Multigov +--- + +# MultiGov Overview + +MultiGov is a multichain governance system that enables decentralized decision-making across multiple blockchain networks. Built on Wormhole messaging, it allows DAOs to manage proposals, voting, and execution from any connected chain without relying on a single hub or bridging assets. It empowers true multichain governance by aggregating voting power across chains and coordinating secure proposal execution. + +## Key Features + +MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: + +- **Multichain governance** – token holders can vote and execute proposals from any supported chain +- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live +- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain +- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity +- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} + +## How It Works + +1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling +2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power +3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification +4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends +5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands + + + +## Use Cases + +- **Cross-Chain Treasury Management** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + +- **Coordinated Protocol Upgrades Across Chains** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + +- **Progressive Decentralization for Multichain DAOs** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + +## Next Steps + +Follow these steps to get started with MultiGov: + +[timeline(wormhole-docs/.snippets/text/products/multigov/multigov-timeline.json)] From cc3b7b95067c39a0029f49cbd039bc14f8c3d3a5 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Mon, 19 May 2025 13:44:59 -0400 Subject: [PATCH 16/55] Pull the latest changes into staging (#404) * update sdk to the latest version (#374) * Add gitignore step (#372) * add instructions for including .gitignore when starting fresh projects * update llms --------- Co-authored-by: Martin Hofmann * update sdk to latest version (#386) * multiple ntt cli feedback adjustments (#389) * multiple ntt cli feedback adjustments * generate llms * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * re-generate llms files --------- Co-authored-by: Erin Shaben * Martinh/faq link in ntt (#384) * add faws link to solana deployment page * llms check * update notes * llm check * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * update based on feedback * llm check * action orientated link * llm check --------- Co-authored-by: Erin Shaben * Martinh/settlement grammar fix (#391) * fix(docs): fix grammar in unified liquidity paragraph (#390) * grammarly check * llm check --------- Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> * remove Connect from product comparison table (#396) * remove Connect from product comparison table * llms check --------- Co-authored-by: Ilaria Enache * Staked rpc comment & feature matrix adjustment (#402) * staked rpc comment for ntt solana deploy * adjust comment * adjust feature support matrix for sui & aptos cctp * re-generate llms files --------- Co-authored-by: Martin Hofmann Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: evgeniko <97796468+evgeniko@users.noreply.github.com> Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Ilaria Enache --- .../deployment-process/post-deployment.md | 2 - llms-files/llms-basics.txt | 106 +- llms-files/llms-connect.txt | 219 +++- llms-files/llms-multigov.txt | 174 ++- llms-files/llms-ntt.txt | 339 +++++- llms-files/llms-queries.txt | 335 +++++- llms-files/llms-relayers.txt | 105 +- llms-files/llms-settlement.txt | 107 +- llms-files/llms-solidity-sdk.txt | 105 +- llms-files/llms-token-bridge.txt | 105 +- llms-files/llms-transfer.txt | 683 +++++++++++- llms-files/llms-typescript-sdk.txt | 105 +- llms-full.txt | 989 +++++++++++++++++- llms.txt | 15 +- .../tutorials/complete-usdc-transfer.md | 14 +- products/connect/reference/support-matrix.md | 4 +- .../tutorials/cross-chain-token-contracts.md | 8 +- .../guides/deploy-to-solana.md | 34 +- products/products.md | 38 +- products/settlement/concepts/architecture.md | 2 +- .../tutorials/transfer-workflow.md | 12 +- variables.yml | 4 +- 22 files changed, 3158 insertions(+), 347 deletions(-) diff --git a/..build/transfers/native-token-transfers/deployment-process/post-deployment.md b/..build/transfers/native-token-transfers/deployment-process/post-deployment.md index 3dfa78984..a98128cfa 100644 --- a/..build/transfers/native-token-transfers/deployment-process/post-deployment.md +++ b/..build/transfers/native-token-transfers/deployment-process/post-deployment.md @@ -21,8 +21,6 @@ By default, NTT transfers to Solana require manual relaying, meaning that after This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. - ## Where to Go Next
diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index deea21c34..cebac9178 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -10,6 +10,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/core-contracts.md [type: other] @@ -965,6 +966,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -985,7 +1053,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -994,23 +1061,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -1018,6 +1084,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index 0832993a3..a00b2c117 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -20,6 +20,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] @@ -1036,6 +1037,115 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Connect +description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +categories: Connect, Transfer +--- + +# Get Started with Connect + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + +- (Optional) To test a transfer from your demo app, you'll need: + + - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} + - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) + +## Install and Setup Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-basic-connect.git + cd demo-basic-connect + ``` + +2. Install the dependencies: + + ```bash + npm install + ``` + +3. Start the application: + + ```bash + npm start + ``` + +4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: + + ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) + +## Configure Connect + +Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: + +```typescript title="App.tsx" +import './App.css'; +import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; + +function App() { + const config: WormholeConnectConfig = { + // Define the network + network: 'Testnet', + + // Define the chains + chains: ['Sui', 'Avalanche'], + + // UI configuration + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + // Define the theme + mode: 'dark', + primary: '#78c4b6', + }; + + return ; +} + +export default App; +``` + +The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: + +- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` +- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains +- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI +- **Defines the theme** - this example sets the mode to `dark` and adds a primary color + +## Interact with Connect + +Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. + +## Next Steps + +For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. + +For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. + + +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- @@ -1630,8 +1740,8 @@ categories: Connect, Transfer | Celo | ✅ | ✅ | ❌ | ❌ | ✅ | | Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | | Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | | Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | | Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | | Base | ✅ | ✅ | ✅ | ✅ | ✅ | @@ -2650,6 +2760,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -2670,7 +2847,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2679,23 +2855,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -2703,6 +2878,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 6198b97e1..06b6d67f3 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -22,6 +22,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/overview.md [type: other] ## Full content for each doc page @@ -382,7 +383,13 @@ categories: MultiGov # MultiGov Architecture -MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. +MultiGov uses a hub-and-spoke architecture to coordinate governance across multiple blockchains. The hub chain is the central controller that handles proposal creation, vote aggregation, and execution. Spoke chains allow token holders to vote locally and can also execute proposal outcomes specific to their network. + +Wormhole’s multichain messaging infrastructure connects the hub and spokes, enabling secure and efficient chain communication. This design allows DAOs to operate seamlessly across ecosystems while maintaining a unified governance process. + +The diagram below illustrates this high-level architecture. + +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) ## Key Components @@ -1046,6 +1053,66 @@ Follow these steps to upgrade the MultiGov Staking Program on Solana: ``` --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/multigov/overview/ +--- BEGIN CONTENT --- +--- +title: MultiGov Overview +description: Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. +categories: Multigov +--- + +# MultiGov Overview + +MultiGov is a multichain governance system that enables decentralized decision-making across multiple blockchain networks. Built on Wormhole messaging, it allows DAOs to manage proposals, voting, and execution from any connected chain without relying on a single hub or bridging assets. It empowers true multichain governance by aggregating voting power across chains and coordinating secure proposal execution. + +## Key Features + +MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: + +- **Multichain governance** – token holders can vote and execute proposals from any supported chain +- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live +- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain +- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity +- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} + +## How It Works + +1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling +2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power +3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification +4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends +5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands + + + +## Use Cases + +- **Cross-Chain Treasury Management** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + +- **Coordinated Protocol Upgrades Across Chains** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + +- **Progressive Decentralization for Multichain DAOs** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + +## Next Steps + +Follow these steps to get started with MultiGov: + +[timeline(wormhole-docs/.snippets/text/products/multigov/multigov-timeline.json)] +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -2003,6 +2070,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -2023,7 +2157,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2032,23 +2165,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -2056,6 +2188,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 2a9d6b5a6..106f78db6 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -24,6 +24,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] @@ -195,8 +196,6 @@ By default, NTT transfers to Solana require manual relaying, meaning that after This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. - ## Where to Go Next
@@ -1061,6 +1060,203 @@ Yes. NTT tokens can be used with chains that do not support NTT by leveraging th This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with NTT +description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. +categories: NTT, Transfer +--- + +# Get Started with NTT + +## Introduction + +The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. + +If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. + +## Prerequisites + +Before you begin, make sure you have: + +- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Bun installed](https://bun.sh/){target=\_blank} +- A wallet private key with tokens on supported chains +- ERC-20 or SPL tokens already deployed on the source and destination chains + +## Don’t Have a Token Yet? + +To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. + +???- interface "Deploy an ERC-20 Token on EVM" + Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. + + 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} + + 2. **Clone the repository** – fetch the example contract repository + + ```bash + git clone https://github.com/wormhole-foundation/example-ntt-token.git + cd example-ntt-token + ``` + + 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses + + ```bash + forge create --broadcast \ + --rpc-url INSERT_RPC_URL \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + src/PeerToken.sol:PeerToken \ + --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS + ``` + + 4. **Mint tokens** – send tokens to your address + + ```bash + cast send INSERT_TOKEN_ADDRESS \ + "mint(address,uint256)" \ + INSERT_RECIPIENT_ADDRESS \ + INSERT_AMOUNT_IN_WEI \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + --rpc-url INSERT_RPC_URL + ``` + + !!! note + This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). + + +???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. + + 1. **Generate a Solana key pair** - run the following command to create a new wallet: + + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` + + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: + + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` + + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: + + === "Mainnet" + ```bash + solana config set -um + ``` + + === "Testnet" + ```bash + solana config set -ut + ``` + + === "Devnet" + ```bash + solana config set -ud + ``` + + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: + + ```bash + solana airdrop 2 + solana balance + ``` + + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} + + ```bash + cargo install spl-token-cli + ``` + + 6. **Create a new SPL token** - initialize the token on Solana + + ```bash + spl-token create-token + ``` + + 7. **Create a token account** - generate an account to hold the token + + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` + + 8. **Mint tokens** - send 1000 tokens to the created account + + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` + + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. + +## Install NTT CLI + +The NTT CLI is recommended to deploy and manage your cross-chain token configuration. + +1. Run the installation command in your terminal: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + +2. Verify the NTT CLI is installed: + + ```bash + ntt --version + ``` + +## Initialize a New NTT Project + +1. Once the CLI is installed, scaffold a new project by running: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +2. Initialize a new `deployment.json` file specifying the network: + + === "Mainnet" + ```bash + ntt init Mainnet + ``` + + === "Testnet" + ```bash + ntt init Testnet + ``` + + After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. + + === "Mainnet" + ```json + { + "network": "Mainnet", + "chains": {} + } + ``` + + === "Testnet" + ```json + { + "network": "Testnet", + "chains": {} + } + ``` + +In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. + +## Next Steps + +You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: + +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- @@ -1392,6 +1588,15 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -1402,19 +1607,13 @@ Before updating the mint authority, you must create metadata for your SPL token. Follow these steps to set the mint authority using the NTT CLI: -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment - - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` - -2. **Derive the token authority** - generate the PDA, which will manage token minting +1. **Derive the token authority** - generate the PDA, which will manage token minting ```bash ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR ``` -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +2. **Set SPL token mint authority** - delegate minting control to the derived PDA ```bash spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA @@ -1422,6 +1621,10 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + + After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: 1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: @@ -1438,8 +1641,7 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON ``` - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. 2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: @@ -1504,6 +1706,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -2838,6 +3048,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -2858,7 +3135,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2867,23 +3143,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -2891,6 +3166,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 43ff33532..0eafb578f 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -16,6 +16,8 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md [type: other] ## Full content for each doc page @@ -598,6 +600,234 @@ It is also important to note that the proxies don't impact the verifiability of Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/queries/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Queries +description: Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. +categories: Queries +--- + +# Get Started with Queries + +## Introduction + +[Queries](/docs/products/queries/overview) lets you fetch on-chain data from supported blockchains using `eth_call`-style requests without submitting transactions or paying gas. The Guardian network signs the result, making it verifiable and suitable for use on-chain. + +This guide walks you through requesting an API key, constructing your first query using the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, and decoding the result. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - A basic understanding of JavaScript or TypeScript + - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia) + - A Wormhole Queries API key + +## Request an API Key + +Wormhole Queries is in closed beta, but you can start building today. + +To interact with the system, you will use the Query Proxy. This hosted service receives your query, routes it to the appropriate chain, and returns a signed, verifiable response from the Guardian network. The Query Proxy allows you to fetch on-chain data without infrastructure overhead. + +To request access, join the beta by filling out the [access form](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. Once approved, you will receive an API key via email. + +## Construct a Query and Decode the Response + +Using the Wormhole Query Proxy, you will write a lightweight script to query a token contract's `name()` on Ethereum Sepolia. The response is signed by the Guardian network and locally decoded for use in your application. + +1. Create a new directory for your script and initialize a Node.js project: + + ```bash + mkdir queries + cd queries + npm init -y + ``` + +2. Add the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, [Axios](https://www.npmjs.com/package/axios){target=\_blank}, [Web3](https://www.npmjs.com/package/web3){target=\_blank}, and helper tools: + + ```bash + npm install axios web3 @wormhole-foundation/wormhole-query-sdk + npm install -D tsx typescript + ``` + +3. Add a new `query.ts` script where you will write and run your query logic: + + ```bash + touch query.ts + ``` + +4. Paste the following script into `query.ts` to build and submit a query to the token contract's `name()` function on Ethereum Sepolia, then decode the Guardian-signed response: + + ```typescript + // Import the SDK types and helpers for making the query +import { + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; +import * as eth from 'web3'; + +// Define the endpoint and query parameters +const query_url = 'https://testnet.query.wormhole.com/v1/query'; +const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public'; +const chain_id = 10002; // Sepolia (Wormhole chain ID) +const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract +const data = '0x06fdde03'; // function selector for `name()` + +// Load your API key from environment variables +const apiKey = process.env.API_KEY; +if (!apiKey) throw new Error('API_KEY is not set in your environment'); + +(async () => { + // Fetch the latest block number (required to anchor the query) + const latestBlock = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + + // Build the query targeting the token contract's name() function + const request = new QueryRequest(1, [ + new PerChainQueryRequest( + chain_id, + new EthCallQueryRequest(latestBlock, [{ to: token, data: data }]) + ), + ]); + const serialized = request.serialize(); + + // Send the query to the Wormhole Query Proxy + const response = await axios.post( + query_url, + { bytes: Buffer.from(serialized).toString('hex') }, + { headers: { 'X-API-Key': apiKey } } + ); + + // Decode the response returned by the Guardian network + const queryResponse = QueryResponse.from(response.data.bytes); + const chainResponse = queryResponse.responses[0] + .response as EthCallQueryResponse; + const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]); + + // Output the results + console.log('\n\nParsed chain response:'); + console.log(chainResponse); + console.log('\nToken name:', name); +})(); + ``` + +5. Use your API key to execute the script: + + ```bash + API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts + ``` + +The expected output should be similar to this: + +
+API_KEY=123_456_789 npx tsx query.ts +Parsed chain response: +EthCallQueryResponse { +blockNumber: 8193548n, +blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8', +blockTime: 1745595132000000n, +results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000'] +} + +Token name: USDC + +
+ +## Next Steps + +Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: + + - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM + - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually + - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts + +Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/queries/overview/ +--- BEGIN CONTENT --- +--- +title: Queries Overview +description: Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. +categories: Queries +--- + +# Queries Overview + +Queries provide on-demand access to Guardian-attested on-chain data. They allow smart contracts to fetch real-time, verifiable data from across the multichain ecosystem, such as prices, rates, and liquidity. + +## Key Features + +- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time +- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation +- **Cross-chain ready** – request data on one chain, use it on another +- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts +- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} + +## How It Works + +A query request follows a simple but robust lifecycle. The off-chain service responsible for handling requests is called the CCQ Server (Cross-Chain Query Server), also referred to as the Query Server throughout this documentation. + +1. An off-chain app sends a query to the CCQ Server via HTTPS +2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} +3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} independently fetch the data, verify it, and sign the result +4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response +5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data + +The CCQ Server is permissioned but trustless. Most queries resolve in under one second, and Guardians retry failed requests for up to one minute. Up to 255 queries can be batched together to optimize performance, supporting efficient multichain workflows. + +![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp) + +## Use Cases + +Queries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + +- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution + - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + +- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + +- **Multichain Prediction Markets** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds + - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + +## Next Steps + +Follow these steps to get started with Queries: + +[timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -1555,6 +1785,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -1575,7 +1872,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -1584,23 +1880,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -1608,6 +1903,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index f00911bc3..6f9497459 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -1508,6 +1508,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -1528,7 +1595,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -1537,23 +1603,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -1561,6 +1626,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index ebf253413..15c00e58e 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -109,7 +109,7 @@ The novel hub-and-spoke liquidity architecture relies on interoperable token sta After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. ### Protocol Flow: How It Works @@ -1503,6 +1503,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -1523,7 +1590,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -1532,23 +1598,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -1556,6 +1621,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 0d1e3d3dc..58620a15c 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -2178,6 +2178,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -2198,7 +2265,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2207,23 +2273,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -2231,6 +2296,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index 1dcf7ba57..ba36643a5 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -1308,6 +1308,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -1328,7 +1395,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -1337,23 +1403,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -1361,6 +1426,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index aca25f23b..291e3d570 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -32,13 +32,16 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] @@ -3193,8 +3196,6 @@ By default, NTT transfers to Solana require manual relaying, meaning that after This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. - ## Where to Go Next
@@ -4746,6 +4747,115 @@ Additional notes: The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Connect +description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +categories: Connect, Transfer +--- + +# Get Started with Connect + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + +- (Optional) To test a transfer from your demo app, you'll need: + + - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} + - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) + +## Install and Setup Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-basic-connect.git + cd demo-basic-connect + ``` + +2. Install the dependencies: + + ```bash + npm install + ``` + +3. Start the application: + + ```bash + npm start + ``` + +4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: + + ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) + +## Configure Connect + +Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: + +```typescript title="App.tsx" +import './App.css'; +import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; + +function App() { + const config: WormholeConnectConfig = { + // Define the network + network: 'Testnet', + + // Define the chains + chains: ['Sui', 'Avalanche'], + + // UI configuration + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + // Define the theme + mode: 'dark', + primary: '#78c4b6', + }; + + return ; +} + +export default App; +``` + +The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: + +- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` +- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains +- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI +- **Defines the theme** - this example sets the mode to `dark` and adds a primary color + +## Interact with Connect + +Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. + +## Next Steps + +For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. + +For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. + + +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- @@ -5340,8 +5450,8 @@ categories: Connect, Transfer | Celo | ✅ | ✅ | ❌ | ❌ | ✅ | | Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | | Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | | Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | | Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | | Base | ✅ | ✅ | ✅ | ✅ | ✅ | @@ -5403,6 +5513,195 @@ This route appears if all of the following conditions are satisfied: - The relayer accepts the selected token to swap into the gas token --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. +categories: Messaging, Transfer +--- + +# Get Started with Messaging + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} + +## Introduction + +Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key +- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} +- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} +- Wallet private key + +## Install and Set Up Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git + cd demo-wormhole-messaging + ``` + +2. Use the following commands to install Foundry and project dependencies: + + ```bash + npm install + ``` + +3. Use Foundry's Forge to compile the contracts in the repository: + + ```bash + forge build + ``` + + You will see terminal output similar to the following, confirming the contracts were compiled successfully: + +
+forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! + +
+ +4. Run tests to ensure everything is functioning correctly before deployment: + + ```bash + forge test + ``` + + You will see passing results for all test cases in the terminal output: + +
+forge test +[⠊] Compiling... +No files changed, compilation skipped +Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest +[PASS] testDeployment() (gas: 13544) +[PASS] testReceiveMessage() (gas: 22579) +[PASS] testSendMessage() (gas: 22719) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) +Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) + +
+ +## Prepare for Contract Deployment + +This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: + +- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji +- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores + +The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. + +### Encrypt Private Key + +Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. + +1. Create a Foundry keystore to encrypt your wallet private key using the following command: + + ```bash + cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY + ``` + +2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: + + ```bash + Enter password: INSERT_DECRYPTION_PASSWORD + ``` + +3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required + +## Deploy Sender Contract + +Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:sender + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run deploy:sender +Enter keystore password: XXXXXXXXXXXX +MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 + +
+ + The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. + +## Deploy Receiver Contract + +Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:receiver + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run deploy:receiver +Enter keystore password: XXXXXXXXXXXX +MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 +Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) + +
+ + - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file + - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji + +## Send Your First Message + +Follow these steps to use your deployed contracts and send your first message: + +1. Run the `sendMessage.ts` script using the following command: + + ```bash + npm run send:message + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run send:message +Enter keystore password: XXXXXXXXXXXX +Transaction sent, waiting for confirmation... +... +Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 +You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET + +
+ +4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: + + ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) + +Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. + +## Next Steps + + +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- @@ -5840,6 +6139,203 @@ Yes. NTT tokens can be used with chains that do not support NTT by leveraging th This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with NTT +description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. +categories: NTT, Transfer +--- + +# Get Started with NTT + +## Introduction + +The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. + +If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. + +## Prerequisites + +Before you begin, make sure you have: + +- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Bun installed](https://bun.sh/){target=\_blank} +- A wallet private key with tokens on supported chains +- ERC-20 or SPL tokens already deployed on the source and destination chains + +## Don’t Have a Token Yet? + +To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. + +???- interface "Deploy an ERC-20 Token on EVM" + Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. + + 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} + + 2. **Clone the repository** – fetch the example contract repository + + ```bash + git clone https://github.com/wormhole-foundation/example-ntt-token.git + cd example-ntt-token + ``` + + 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses + + ```bash + forge create --broadcast \ + --rpc-url INSERT_RPC_URL \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + src/PeerToken.sol:PeerToken \ + --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS + ``` + + 4. **Mint tokens** – send tokens to your address + + ```bash + cast send INSERT_TOKEN_ADDRESS \ + "mint(address,uint256)" \ + INSERT_RECIPIENT_ADDRESS \ + INSERT_AMOUNT_IN_WEI \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + --rpc-url INSERT_RPC_URL + ``` + + !!! note + This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). + + +???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. + + 1. **Generate a Solana key pair** - run the following command to create a new wallet: + + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` + + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: + + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` + + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: + + === "Mainnet" + ```bash + solana config set -um + ``` + + === "Testnet" + ```bash + solana config set -ut + ``` + + === "Devnet" + ```bash + solana config set -ud + ``` + + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: + + ```bash + solana airdrop 2 + solana balance + ``` + + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} + + ```bash + cargo install spl-token-cli + ``` + + 6. **Create a new SPL token** - initialize the token on Solana + + ```bash + spl-token create-token + ``` + + 7. **Create a token account** - generate an account to hold the token + + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` + + 8. **Mint tokens** - send 1000 tokens to the created account + + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` + + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. + +## Install NTT CLI + +The NTT CLI is recommended to deploy and manage your cross-chain token configuration. + +1. Run the installation command in your terminal: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + +2. Verify the NTT CLI is installed: + + ```bash + ntt --version + ``` + +## Initialize a New NTT Project + +1. Once the CLI is installed, scaffold a new project by running: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +2. Initialize a new `deployment.json` file specifying the network: + + === "Mainnet" + ```bash + ntt init Mainnet + ``` + + === "Testnet" + ```bash + ntt init Testnet + ``` + + After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. + + === "Mainnet" + ```json + { + "network": "Mainnet", + "chains": {} + } + ``` + + === "Testnet" + ```json + { + "network": "Testnet", + "chains": {} + } + ``` + +In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. + +## Next Steps + +You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: + +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- @@ -6171,6 +6667,15 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -6181,19 +6686,13 @@ Before updating the mint authority, you must create metadata for your SPL token. Follow these steps to set the mint authority using the NTT CLI: -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment - - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` - -2. **Derive the token authority** - generate the PDA, which will manage token minting +1. **Derive the token authority** - generate the PDA, which will manage token minting ```bash ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR ``` -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +2. **Set SPL token mint authority** - delegate minting control to the derived PDA ```bash spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA @@ -6201,6 +6700,10 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + + After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: 1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: @@ -6217,8 +6720,7 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON ``` - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. 2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: @@ -6283,6 +6785,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -6680,7 +7190,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -6689,23 +7198,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -6713,6 +7221,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. @@ -6762,7 +7274,7 @@ The novel hub-and-spoke liquidity architecture relies on interoperable token sta After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. ### Protocol Flow: How It Works @@ -8196,6 +8708,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -8216,7 +8795,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -8225,23 +8803,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -8249,6 +8826,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 18468b532..4baf787ce 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -4429,6 +4429,73 @@ See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- @@ -4449,7 +4516,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -4458,23 +4524,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -4482,6 +4547,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/llms-full.txt b/llms-full.txt index f30cbc05b..46fb3e6f7 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -30,6 +30,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md @@ -4856,8 +4857,6 @@ By default, NTT transfers to Solana require manual relaying, meaning that after This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -[Wormhole Connect](/docs/build/applications/connect/){target=\_blank} support this process automatically. - ## Where to Go Next
@@ -5921,6 +5920,41 @@ The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardia A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/ai-resources/ai-resources/ +--- BEGIN CONTENT --- +--- +title: AI Resources +description: Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. +--- + +# AI Resources +Wormhole provides `.txt` files containing the documentation content and navigation structure, optimized for use with large language models (LLMs) and AI tools. These resources help build AI assistants, power code search, or enable custom tooling trained on Wormhole’s docs. + +Each category file includes foundational content from the **Basics** and **Reference** categories to ensure LLMs have the necessary context. + +## Download LLM Files + + +| Category | Description | File | Actions | +|----------------|-------------------|-------|----------| +| Index | Navigation index of all Wormhole documentation pages | `llms.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms.txt" } [:octicons-download-16:](/docs/llms.txt){ download="llms.txt" } | +| Full Documentation | Full content of all documentation pages | `llms-full.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-full.txt" } [:octicons-download-16:](/docs/llms-full.txt){ download="llms-full.txt" } | +| Basics | Wormhole's architecture, security, and core components to help understand how the protocol works | `llms-basics.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-basics.txt" } [:octicons-download-16:](/docs/llms-files/llms-basics.txt){ download="llms-basics.txt" } | +| Reference | Reference details such as chain IDs, contract addresses, and finality levels | `llms-reference.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-reference.txt"} [:octicons-download-16:](/docs/llms-files/llms-reference.txt){ download="llms-reference.txt" } | +| NTT | All NTT docs, including architecture, deployment guides, CLI usage, and configuration for EVM and Solana | `llms-ntt.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-ntt.txt" } [:octicons-download-16:](/docs/llms-files/llms-ntt.txt){ download="llms-ntt.txt" } | +| Connect | Setup, features, and configuration details for integrating the Connect widget into your dApp | `llms-connect.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-connect.txt" } [:octicons-download-16:](/docs/llms-files/llms-connect.txt){ download="llms-connect.txt" } | +| Token Bridge | Architecture overview, transfer flows, and smart contract methods for cross-chain token transfers using the Token Bridge | `llms-token-bridge.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-token-bridge.txt" } [:octicons-download-16:](/docs/llms-files/llms-token-bridge.txt){ download="llms-token-bridge.txt" } | +| Settlement | Architecture, integration guides, and setup instructions for building on the Wormhole Settlement protocol | `llms-settlement.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-settlement.txt" } [:octicons-download-16:](/docs/llms-files/llms-settlement.txt){ download="llms-settlement.txt" } | +| Relayers | Guides and reference for using Wormhole’s Relayer module, building cross-chain messaging contracts, and running custom relayers | `llms-relayers.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-relayers.txt" } [:octicons-download-16:](/docs/llms-files/llms-relayers.txt){ download="llms-relayers.txt" } | +| MultiGov | Architecture, deployment steps, and upgrade instructions for multichain governance on EVM and Solana | `llms-multigov.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-multigov.txt" } [:octicons-download-16:](/docs/llms-files/llms-multigov.txt){ download="llms-multigov.txt" } | +| Queries | Guides for using the Wormhole Query SDK and Proxy to construct, test, and verify on-chain data queries across chains | `llms-queries.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-queries.txt" } [:octicons-download-16:](/docs/llms-files/llms-queries.txt){ download="llms-queries.txt" } | +| Solidity SDK | SDK docs for cross-chain messaging, token transfers, relayer integration, and local testing in Solidity | `llms-solidity-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-solidity-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-solidity-sdk.txt){ download="llms-solidity-sdk.txt" } | +| TypeScript SDK | Docs for working with VAAs, payloads, and cross-chain message structures using the TypeScript SDK | `llms-typescript-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-typescript-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-typescript-sdk.txt){ download="llms-typescript-sdk.txt" } | + +!!! note + The `llms-full.txt` file may exceed the input limits of some language models due to its size. If you encounter limitations, consider using the files by category. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/cctp-bridge/concepts/integration/ --- BEGIN CONTENT --- TODO @@ -5995,13 +6029,19 @@ In this section, you'll set up your project for transferring USDC across chains npm init -y ``` -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries ```bash npm install @wormhole-foundation/sdk dotenv ``` -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project ```bash touch .env @@ -6017,7 +6057,7 @@ In this section, you'll set up your project for transferring USDC across chains !!! note Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays 1. Create the helpers file @@ -6093,7 +6133,7 @@ export async function getSigner( - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file -5. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains +6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains 1. Create the `manual-transfer.ts` file in the `src` directory @@ -7847,7 +7887,111 @@ Additional notes: Doc-Content: https://wormhole.com/docs/products/connect/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with Connect +description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +categories: Connect, Transfer +--- + +# Get Started with Connect + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + +## Introduction + +Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + +- (Optional) To test a transfer from your demo app, you'll need: + + - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} + - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) + +## Install and Setup Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-basic-connect.git + cd demo-basic-connect + ``` + +2. Install the dependencies: + + ```bash + npm install + ``` + +3. Start the application: + + ```bash + npm start + ``` + +4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: + + ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) + +## Configure Connect + +Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: + +```typescript title="App.tsx" +import './App.css'; +import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; + +function App() { + const config: WormholeConnectConfig = { + // Define the network + network: 'Testnet', + + // Define the chains + chains: ['Sui', 'Avalanche'], + + // UI configuration + ui: { + title: 'SUI Connect TS Demo', + }, + }; + + const theme: WormholeConnectTheme = { + // Define the theme + mode: 'dark', + primary: '#78c4b6', + }; + + return ; +} + +export default App; +``` + +The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: + +- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` +- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains +- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI +- **Defines the theme** - this example sets the mode to `dark` and adds a primary color + +## Interact with Connect + +Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. + +## Next Steps + +For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. + +For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. + + --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ @@ -8449,8 +8593,8 @@ categories: Connect, Transfer | Celo | ✅ | ✅ | ❌ | ❌ | ✅ | | Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | | Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | | Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | | Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | | Base | ✅ | ✅ | ✅ | ✅ | ✅ | @@ -8699,7 +8843,191 @@ With these tools and knowledge, you’re now equipped to build powerful cross-ch Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with Messaging +description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. +categories: Messaging, Transfer +--- + +# Get Started with Messaging + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} + +## Introduction + +Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. + +## Prerequisites + +Before you begin, make sure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key +- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} +- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} +- Wallet private key + +## Install and Set Up Project + +1. Clone the demo repository and navigate to the project directory: + + ```bash + git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git + cd demo-wormhole-messaging + ``` + +2. Use the following commands to install Foundry and project dependencies: + + ```bash + npm install + ``` + +3. Use Foundry's Forge to compile the contracts in the repository: + + ```bash + forge build + ``` + + You will see terminal output similar to the following, confirming the contracts were compiled successfully: + +
+forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! + +
+ +4. Run tests to ensure everything is functioning correctly before deployment: + + ```bash + forge test + ``` + + You will see passing results for all test cases in the terminal output: + +
+forge test +[⠊] Compiling... +No files changed, compilation skipped +Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest +[PASS] testDeployment() (gas: 13544) +[PASS] testReceiveMessage() (gas: 22579) +[PASS] testSendMessage() (gas: 22719) +Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) +Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) + +
+ +## Prepare for Contract Deployment + +This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: + +- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji +- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores + +The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. + +### Encrypt Private Key + +Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. + +1. Create a Foundry keystore to encrypt your wallet private key using the following command: + + ```bash + cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY + ``` + +2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: + + ```bash + Enter password: INSERT_DECRYPTION_PASSWORD + ``` + +3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required + +## Deploy Sender Contract + +Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:sender + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run deploy:sender +Enter keystore password: XXXXXXXXXXXX +MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 + +
+ + The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. + +## Deploy Receiver Contract + +Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: + +1. Run the deployment script command in your terminal: + + ```bash + npm run deploy:receiver + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run deploy:receiver +Enter keystore password: XXXXXXXXXXXX +MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 +Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) + +
+ + - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file + - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji + +## Send Your First Message + +Follow these steps to use your deployed contracts and send your first message: + +1. Run the `sendMessage.ts` script using the following command: + + ```bash + npm run send:message + ``` + +2. Enter your Foundry keystore password in the terminal when prompted + +3. You will see terminal output similar to the following: + +
+npm run send:message +Enter keystore password: XXXXXXXXXXXX +Transaction sent, waiting for confirmation... +... +Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 +You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET + +
+ +4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: + + ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) + +Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. + +## Next Steps + + --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ @@ -9287,7 +9615,69 @@ For detailed, step-by-step guidance on creating cross-chain contracts that inter Doc-Content: https://wormhole.com/docs/products/messaging/overview/ --- BEGIN CONTENT --- -TODO +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- + +# Messaging Overview + +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. + +## Key Features + +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases + +## How It Works + +The messaging flow consists of several core components: + +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + +## Use Cases + +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + +- **Gas Abstraction** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + +- **Bridging Intent Library** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + +## Next Steps + +Follow these steps to work with Wormhole Messaging: + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ @@ -10699,8 +11089,14 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract ```bash npm init -y ``` + + 2. Create a `.gitignore` file to ensure your private key isn't accidentally exposed or committed to version control: + + ```bash + echo ".env" >> .gitignore + ``` - 2. Install the necessary dependencies: + 3. Install the necessary dependencies: ```bash npm install ethers dotenv readline-sync @types/readline-sync @@ -12931,7 +13327,13 @@ categories: MultiGov # MultiGov Architecture -MultiGov employs a hub-and-spoke model to enable cross-chain governance, utilizing Wormhole's interoperability infrastructure for secure cross-chain communication. This architecture allows coordinated decision-making across multiple blockchain networks while maintaining a central coordination point. +MultiGov uses a hub-and-spoke architecture to coordinate governance across multiple blockchains. The hub chain is the central controller that handles proposal creation, vote aggregation, and execution. Spoke chains allow token holders to vote locally and can also execute proposal outcomes specific to their network. + +Wormhole’s multichain messaging infrastructure connects the hub and spokes, enabling secure and efficient chain communication. This design allows DAOs to operate seamlessly across ecosystems while maintaining a unified governance process. + +The diagram below illustrates this high-level architecture. + +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) ## Key Components @@ -13602,7 +14004,62 @@ Follow these steps to upgrade the MultiGov Staking Program on Solana: Doc-Content: https://wormhole.com/docs/products/multigov/overview/ --- BEGIN CONTENT --- -TODO +--- +title: MultiGov Overview +description: Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. +categories: Multigov +--- + +# MultiGov Overview + +MultiGov is a multichain governance system that enables decentralized decision-making across multiple blockchain networks. Built on Wormhole messaging, it allows DAOs to manage proposals, voting, and execution from any connected chain without relying on a single hub or bridging assets. It empowers true multichain governance by aggregating voting power across chains and coordinating secure proposal execution. + +## Key Features + +MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: + +- **Multichain governance** – token holders can vote and execute proposals from any supported chain +- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live +- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain +- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity +- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} + +## How It Works + +1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling +2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power +3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification +4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends +5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands + + + +## Use Cases + +- **Cross-Chain Treasury Management** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + +- **Coordinated Protocol Upgrades Across Chains** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + +- **Progressive Decentralization for Multichain DAOs** + + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + +## Next Steps + +Follow these steps to get started with MultiGov: + +[timeline(wormhole-docs/.snippets/text/products/multigov/multigov-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ @@ -14261,7 +14718,199 @@ This approach ensures interoperability while maintaining the integrity of the to Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with NTT +description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. +categories: NTT, Transfer +--- + +# Get Started with NTT + +## Introduction + +The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. + +If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. + +## Prerequisites + +Before you begin, make sure you have: + +- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Bun installed](https://bun.sh/){target=\_blank} +- A wallet private key with tokens on supported chains +- ERC-20 or SPL tokens already deployed on the source and destination chains + +## Don’t Have a Token Yet? + +To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. + +???- interface "Deploy an ERC-20 Token on EVM" + Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. + + 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} + + 2. **Clone the repository** – fetch the example contract repository + + ```bash + git clone https://github.com/wormhole-foundation/example-ntt-token.git + cd example-ntt-token + ``` + + 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses + + ```bash + forge create --broadcast \ + --rpc-url INSERT_RPC_URL \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + src/PeerToken.sol:PeerToken \ + --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS + ``` + + 4. **Mint tokens** – send tokens to your address + + ```bash + cast send INSERT_TOKEN_ADDRESS \ + "mint(address,uint256)" \ + INSERT_RECIPIENT_ADDRESS \ + INSERT_AMOUNT_IN_WEI \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + --rpc-url INSERT_RPC_URL + ``` + + !!! note + This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). + + +???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. + + 1. **Generate a Solana key pair** - run the following command to create a new wallet: + + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` + + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: + + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` + + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: + + === "Mainnet" + ```bash + solana config set -um + ``` + + === "Testnet" + ```bash + solana config set -ut + ``` + + === "Devnet" + ```bash + solana config set -ud + ``` + + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: + + ```bash + solana airdrop 2 + solana balance + ``` + + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} + + ```bash + cargo install spl-token-cli + ``` + + 6. **Create a new SPL token** - initialize the token on Solana + + ```bash + spl-token create-token + ``` + + 7. **Create a token account** - generate an account to hold the token + + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` + + 8. **Mint tokens** - send 1000 tokens to the created account + + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` + + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. + +## Install NTT CLI + +The NTT CLI is recommended to deploy and manage your cross-chain token configuration. + +1. Run the installation command in your terminal: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + +2. Verify the NTT CLI is installed: + + ```bash + ntt --version + ``` + +## Initialize a New NTT Project + +1. Once the CLI is installed, scaffold a new project by running: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +2. Initialize a new `deployment.json` file specifying the network: + + === "Mainnet" + ```bash + ntt init Mainnet + ``` + + === "Testnet" + ```bash + ntt init Testnet + ``` + + After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. + + === "Mainnet" + ```json + { + "network": "Mainnet", + "chains": {} + } + ``` + + === "Testnet" + ```json + { + "network": "Testnet", + "chains": {} + } + ``` + +In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. + +## Next Steps + +You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: + +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ @@ -14595,6 +15244,15 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -14605,19 +15263,13 @@ Before updating the mint authority, you must create metadata for your SPL token. Follow these steps to set the mint authority using the NTT CLI: -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment - - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` - -2. **Derive the token authority** - generate the PDA, which will manage token minting +1. **Derive the token authority** - generate the PDA, which will manage token minting ```bash ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR ``` -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +2. **Set SPL token mint authority** - delegate minting control to the derived PDA ```bash spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA @@ -14625,6 +15277,10 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + + After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: 1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: @@ -14641,8 +15297,7 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON ``` - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. 2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: @@ -14707,6 +15362,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -15109,7 +15772,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -15118,23 +15780,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -15142,6 +15803,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. @@ -15212,7 +15877,158 @@ Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Doc-Content: https://wormhole.com/docs/products/queries/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with Queries +description: Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. +categories: Queries +--- + +# Get Started with Queries + +## Introduction + +[Queries](/docs/products/queries/overview) lets you fetch on-chain data from supported blockchains using `eth_call`-style requests without submitting transactions or paying gas. The Guardian network signs the result, making it verifiable and suitable for use on-chain. + +This guide walks you through requesting an API key, constructing your first query using the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, and decoding the result. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - A basic understanding of JavaScript or TypeScript + - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia) + - A Wormhole Queries API key + +## Request an API Key + +Wormhole Queries is in closed beta, but you can start building today. + +To interact with the system, you will use the Query Proxy. This hosted service receives your query, routes it to the appropriate chain, and returns a signed, verifiable response from the Guardian network. The Query Proxy allows you to fetch on-chain data without infrastructure overhead. + +To request access, join the beta by filling out the [access form](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. Once approved, you will receive an API key via email. + +## Construct a Query and Decode the Response + +Using the Wormhole Query Proxy, you will write a lightweight script to query a token contract's `name()` on Ethereum Sepolia. The response is signed by the Guardian network and locally decoded for use in your application. + +1. Create a new directory for your script and initialize a Node.js project: + + ```bash + mkdir queries + cd queries + npm init -y + ``` + +2. Add the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, [Axios](https://www.npmjs.com/package/axios){target=\_blank}, [Web3](https://www.npmjs.com/package/web3){target=\_blank}, and helper tools: + + ```bash + npm install axios web3 @wormhole-foundation/wormhole-query-sdk + npm install -D tsx typescript + ``` + +3. Add a new `query.ts` script where you will write and run your query logic: + + ```bash + touch query.ts + ``` + +4. Paste the following script into `query.ts` to build and submit a query to the token contract's `name()` function on Ethereum Sepolia, then decode the Guardian-signed response: + + ```typescript + // Import the SDK types and helpers for making the query +import { + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; +import * as eth from 'web3'; + +// Define the endpoint and query parameters +const query_url = 'https://testnet.query.wormhole.com/v1/query'; +const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public'; +const chain_id = 10002; // Sepolia (Wormhole chain ID) +const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract +const data = '0x06fdde03'; // function selector for `name()` + +// Load your API key from environment variables +const apiKey = process.env.API_KEY; +if (!apiKey) throw new Error('API_KEY is not set in your environment'); + +(async () => { + // Fetch the latest block number (required to anchor the query) + const latestBlock = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + + // Build the query targeting the token contract's name() function + const request = new QueryRequest(1, [ + new PerChainQueryRequest( + chain_id, + new EthCallQueryRequest(latestBlock, [{ to: token, data: data }]) + ), + ]); + const serialized = request.serialize(); + + // Send the query to the Wormhole Query Proxy + const response = await axios.post( + query_url, + { bytes: Buffer.from(serialized).toString('hex') }, + { headers: { 'X-API-Key': apiKey } } + ); + + // Decode the response returned by the Guardian network + const queryResponse = QueryResponse.from(response.data.bytes); + const chainResponse = queryResponse.responses[0] + .response as EthCallQueryResponse; + const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]); + + // Output the results + console.log('\n\nParsed chain response:'); + console.log(chainResponse); + console.log('\nToken name:', name); +})(); + ``` + +5. Use your API key to execute the script: + + ```bash + API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts + ``` + +The expected output should be similar to this: + +
+API_KEY=123_456_789 npx tsx query.ts +Parsed chain response: +EthCallQueryResponse { +blockNumber: 8193548n, +blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8', +blockTime: 1745595132000000n, +results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000'] +} + +Token name: USDC + +
+ +## Next Steps + +Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: + + - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM + - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually + - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts + +Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/guides/construct-a-query/ @@ -15232,7 +16048,7 @@ TODO Doc-Content: https://wormhole.com/docs/products/queries/guides/submit-response/ --- BEGIN CONTENT --- - +TODO --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/guides/verify-response/ @@ -15242,7 +16058,74 @@ TODO Doc-Content: https://wormhole.com/docs/products/queries/overview/ --- BEGIN CONTENT --- -TODO +--- +title: Queries Overview +description: Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. +categories: Queries +--- + +# Queries Overview + +Queries provide on-demand access to Guardian-attested on-chain data. They allow smart contracts to fetch real-time, verifiable data from across the multichain ecosystem, such as prices, rates, and liquidity. + +## Key Features + +- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time +- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation +- **Cross-chain ready** – request data on one chain, use it on another +- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts +- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} + +## How It Works + +A query request follows a simple but robust lifecycle. The off-chain service responsible for handling requests is called the CCQ Server (Cross-Chain Query Server), also referred to as the Query Server throughout this documentation. + +1. An off-chain app sends a query to the CCQ Server via HTTPS +2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} +3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} independently fetch the data, verify it, and sign the result +4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response +5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data + +The CCQ Server is permissioned but trustless. Most queries resolve in under one second, and Guardians retry failed requests for up to one minute. Up to 255 queries can be batched together to optimize performance, supporting efficient multichain workflows. + +![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp) + +## Use Cases + +Queries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them. + +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + +- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution + - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + +- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + +- **Multichain Prediction Markets** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds + - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + + - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains + - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + +## Next Steps + +Follow these steps to get started with Queries: + +[timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ @@ -16151,7 +17034,7 @@ The novel hub-and-spoke liquidity architecture relies on interoperable token sta After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. ### Protocol Flow: How It Works @@ -16969,13 +17852,19 @@ In this section, we’ll guide you through initializing the project, installing npm init -y ``` -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries ```bash npm install @wormhole-foundation/sdk dotenv tsx ``` -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project ```bash touch .env @@ -16992,7 +17881,7 @@ In this section, we’ll guide you through initializing the project, installing !!! note Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays 1. Create the helpers file diff --git a/llms.txt b/llms.txt index 252b784f5..81125d3c8 100644 --- a/llms.txt +++ b/llms.txt @@ -28,6 +28,7 @@ - [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md): Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. - [Wormhole Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md): Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. - [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. +- [AI Resources](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md): Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md): No description available. @@ -38,15 +39,15 @@ - [Connect Data Configuration](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md): Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. - [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. - [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md): No description available. +- [Get Started with Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md): Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. - [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md): No description available. - [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. - [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md): No description available. +- [Get Started with Messaging](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md): Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. - [Get Started with Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md): This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts - [Wormhole-Deployed Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md): Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md): No description available. +- [Messaging Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md): With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. - [Create Cross-Chain Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-contracts.md): Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. - [Cross-Chain Token Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/cross-chain-token-contracts.md): Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. - [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. @@ -57,14 +58,14 @@ - [MultiGov Deployment to Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md): Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. - [Upgrading MultiGov on EVM](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md): Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. - [Upgrading MultiGov on Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-solana.md): Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/overview.md): No description available. +- [MultiGov Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/overview.md): Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. - [MultiGov Guides](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md): Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. - [Native Token Transfers Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md): Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. - [Native Token Transfers Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md): Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. - [Native Token Transfers Access Control](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md): Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. - [Native Token Transfers Rate Limiting](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/rate-limiting.md): Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. - [Native Token Transfers FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/faqs.md): Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md): No description available. +- [Get Started with NTT](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/get-started.md): NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. - [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. @@ -74,13 +75,13 @@ - [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md): No description available. - [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md): No description available. +- [Get Started with Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md): Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/construct-a-query.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/mock-a-query.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/query-request.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md): No description available. +- [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md): Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md): No description available. - [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. diff --git a/products/cctp-bridge/tutorials/complete-usdc-transfer.md b/products/cctp-bridge/tutorials/complete-usdc-transfer.md index 84b0968a4..aea742857 100644 --- a/products/cctp-bridge/tutorials/complete-usdc-transfer.md +++ b/products/cctp-bridge/tutorials/complete-usdc-transfer.md @@ -50,13 +50,19 @@ In this section, you'll set up your project for transferring USDC across chains npm init -y ``` -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries ```bash npm install @wormhole-foundation/sdk dotenv ``` -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project ```bash touch .env @@ -72,7 +78,7 @@ In this section, you'll set up your project for transferring USDC across chains !!! note Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays 1. Create the helpers file @@ -90,7 +96,7 @@ In this section, you'll set up your project for transferring USDC across chains - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file -5. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains +6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains 1. Create the `manual-transfer.ts` file in the `src` directory diff --git a/products/connect/reference/support-matrix.md b/products/connect/reference/support-matrix.md index 2ba6242ba..329f04d58 100644 --- a/products/connect/reference/support-matrix.md +++ b/products/connect/reference/support-matrix.md @@ -20,8 +20,8 @@ categories: Connect, Transfer | Celo | ✅ | ✅ | ❌ | ❌ | ✅ | | Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | | Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ❌ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | | Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | | Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | | Base | ✅ | ✅ | ✅ | ✅ | ✅ | diff --git a/products/messaging/tutorials/cross-chain-token-contracts.md b/products/messaging/tutorials/cross-chain-token-contracts.md index f540c99df..2eb4a9bba 100644 --- a/products/messaging/tutorials/cross-chain-token-contracts.md +++ b/products/messaging/tutorials/cross-chain-token-contracts.md @@ -269,8 +269,14 @@ Now that you've written the `CrossChainSender` and `CrossChainReceiver` contract ```bash npm init -y ``` + + 2. Create a `.gitignore` file to ensure your private key isn't accidentally exposed or committed to version control: + + ```bash + echo ".env" >> .gitignore + ``` - 2. Install the necessary dependencies: + 3. Install the necessary dependencies: ```bash npm install ethers dotenv readline-sync @types/readline-sync diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index df75635cb..56333a44c 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -137,6 +137,15 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -147,19 +156,13 @@ Before updating the mint authority, you must create metadata for your SPL token. Follow these steps to set the mint authority using the NTT CLI: -1. **Generate an NTT program key pair** - create a unique key pair for the NTT program. The key pair must start with "ntt" to identify it as belonging to the NTT deployment - - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` - -2. **Derive the token authority** - generate the PDA, which will manage token minting +1. **Derive the token authority** - generate the PDA, which will manage token minting ```bash ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR ``` -3. **Set SPL token mint authority** - delegate minting control to the derived PDA +2. **Set SPL token mint authority** - delegate minting control to the derived PDA ```bash spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA @@ -167,6 +170,10 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + + After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: 1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: @@ -183,8 +190,7 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON ``` - !!! tip - The `add-chain` command accepts an optional `--solana-priority-fee` flag, which sets the priority fee in microlamports. The default is `50000`. + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. 2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: @@ -249,4 +255,12 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
diff --git a/products/products.md b/products/products.md index 4a8e41412..2356ffba3 100644 --- a/products/products.md +++ b/products/products.md @@ -16,7 +16,6 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Connect**](/docs/products/connect/overview/){target=\_blank} - a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -25,23 +24,22 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe ::spantable:: -| | Criteria | Connect | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :white_check_mark: | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :x: | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | | -| Requirements @span | Contract Deployment | :x: | :white_check_mark: | :x: |:x: | -| Ecosystem Support | Integrates with Other Products | :white_check_mark: | :white_check_mark: | :white_check_mark: |:white_check_mark: | -| Ease of Integration | Implementation Complexity | :green_circle: :white_circle: :white_circle:
Low | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | -| Technology @span | Supported Languages | JavaScript, TypeScript | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
Moderate | :green_circle: :green_circle: :white_circle:
Moderate |:green_circle: :white_circle: :white_circle:
Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | ::end-spantable:: @@ -49,6 +47,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. +## Bridging UI + +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + ## Real-time Data [**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. diff --git a/products/settlement/concepts/architecture.md b/products/settlement/concepts/architecture.md index 77291f3c6..a3eb8a6d5 100644 --- a/products/settlement/concepts/architecture.md +++ b/products/settlement/concepts/architecture.md @@ -36,7 +36,7 @@ The novel hub-and-spoke liquidity architecture relies on interoperable token sta After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity—eliminating the need for solver "buy-in" for new chain expansion. Additionally, this means new chains, even without proven traction, can access the same amount of liquidity for cross-chain intent fulfillment from day one of mainnet launch as they would if they were long-standing ecosystems with clear evidence of adoption — commonly overlooked by solvers who must aggressively prioritize high flow chains to due high opportunity costs. This includes new ecosystems without Centralized Exchange (CEX) enabled withdrawals. +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. ### Protocol Flow: How It Works diff --git a/products/token-bridge/tutorials/transfer-workflow.md b/products/token-bridge/tutorials/transfer-workflow.md index bc74bb4c0..878f2e1e5 100644 --- a/products/token-bridge/tutorials/transfer-workflow.md +++ b/products/token-bridge/tutorials/transfer-workflow.md @@ -47,13 +47,19 @@ In this section, we’ll guide you through initializing the project, installing npm init -y ``` -2. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries ```bash npm install @wormhole-foundation/sdk dotenv tsx ``` -3. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project ```bash touch .env @@ -70,7 +76,7 @@ In this section, we’ll guide you through initializing the project, installing !!! note Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. -4. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays 1. Create the helpers file diff --git a/variables.yml b/variables.yml index e473eedf5..a06eeca9c 100644 --- a/variables.yml +++ b/variables.yml @@ -1,10 +1,10 @@ ntt: anchor_version: v0.29.0 - solana_cli_version: v1.18.26 + solana_cli_version: v1.18.10 repositories: wormhole_sdk: repository_url: https://github.com/wormhole-foundation/wormhole-sdk-ts - version: 1.15.3 + version: 1.17.0 wormhole: repository_url: https://github.com/wormhole-foundation/wormhole version: 2.33.0 From 2609cea64b81a790c728cc2b458b1e9f95361b12 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Mon, 19 May 2025 20:07:40 +0200 Subject: [PATCH 17/55] Multigov - Get Started page (#379) * first draft multigov get started * grammarly check * add metadate description * add tally links * link to next sections * update title and metadata * Apply suggestions from code review Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * reorg * rewording * rewording * multigov overview page * multigov overview page * multigov overview page * Update products/multigov/get-started.md Co-authored-by: Erin Shaben * update metadata categories * update intro and wording * future proof update * remove prerequisite * update prerequisites * multigov timeline * remove step and update style * small fix * update supported chains * update next steps * add reference to token deployment * add token specifications * add link to overview * Update .snippets/text/products/multigov/multigov-timeline.json Co-authored-by: Erin Shaben * Apply feedback * move diagram to architecture page * add deploymment flow * unfinished timeline * update timeline * Update products/multigov/get-started.md Co-authored-by: Erin Shaben * Update products/multigov/get-started.md * updated timeline * fix capitalization * Apply suggestions from code review Co-authored-by: Erin Shaben * Update .snippets/text/products/multigov/deployment-flow-timeline.json Co-authored-by: Erin Shaben * update timeline --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --- .../multigov/deployment-flow-timeline.json | 27 +++++++++++ products/multigov/get-started.md | 47 ++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 .snippets/text/products/multigov/deployment-flow-timeline.json diff --git a/.snippets/text/products/multigov/deployment-flow-timeline.json b/.snippets/text/products/multigov/deployment-flow-timeline.json new file mode 100644 index 000000000..d4f0178bb --- /dev/null +++ b/.snippets/text/products/multigov/deployment-flow-timeline.json @@ -0,0 +1,27 @@ +[ + { + "title": "Clone The MultiGov Repository", + "content": "Download the [codebase](https://github.com/wormhole-foundation/multigov) and navigate to the appropriate folder (`evm` or `solana`).", + "icon": ":fontawesome-solid-1:" + }, + { + "title": "Set Up Your Project", + "content": "Install the required toolchain for your target network. For EVM, use Foundry (or similar); for Solana, use Anchor (or similar), Solana CLI, and Rust.", + "icon": ":fontawesome-solid-2:" + }, + { + "title": "Configure Deployment Settings", + "content": "Set environment variables such as RPC URLs, keypairs, and hub chain details in a `.env` file or Anchor config.", + "icon": ":fontawesome-solid-3:" + }, + { + "title": "Deploy MultiGov Contracts or Programs", + "content": "Use the provided scripts to deploy the hub (EVM only) and spoke components (EVM or Solana) to your selected networks.", + "icon": ":fontawesome-solid-4:" + }, + { + "title": "Initialize Governance Configuration", + "content": "Set voting parameters, authorities, and metadata. Use deployment scripts or governance proposals depending on your setup.", + "icon": ":fontawesome-solid-5:" + } +] diff --git a/products/multigov/get-started.md b/products/multigov/get-started.md index 30404ce4c..3691e7203 100644 --- a/products/multigov/get-started.md +++ b/products/multigov/get-started.md @@ -1 +1,46 @@ -TODO \ No newline at end of file +--- +title: Get Started with Multigov +description: Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. +categories: MultiGov +--- + +# Get Started with Multigov + +## Introduction + +[MultiGov](/docs/products/multigov/overview/){target=\_blank} enables multichain governance using Wormhole messaging. With MultiGov, token holders can create proposals, vote, and execute decisions from any supported chain, eliminating the need to bridge assets or rely on a single governance hub. + +This page walks you through the MultiGov deployment flow—from requesting access with Tally to choosing a network and following the appropriate deployment guide. + +## Prerequisites + +Before deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL): + +- **EVM chains**: + - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\_blank} standard + - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting + +- **Solana**: + - Use an SPL token + - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\_blank} + +## Request Tally Access + +MultiGov integrations are coordinated through [Tally](https://www.tally.xyz/explore){target=\_blank}, a multichain governance platform that powers proposal creation, voting, and execution. + +To get started, fill out the integration [intake form](https://www.tally.xyz/get-started){target=\_blank}. The Tally team will review your application and contact you to discuss deployment and setup requirements. + +Once approved, review the deployment flow below to understand the integration process. Then, follow the appropriate deployment guide to integrate MultiGov with your governance token on EVM chains, Solana, or other supported networks. + +## Deployment Flow + +MultiGov deployments follow a similar structure on both EVM and Solana. This section provides a high-level overview of the end-to-end flow. Each step is explained in more detail in the platform-specific deployment guides linked [below](#next-steps). + +[timeline(wormhole-docs/.snippets/text/products/multigov/deployment-flow-timeline.json)] + +## Next Steps + +You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: + + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation From 086ed52db18abedb33ba9b71dad66833e7689875 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Mon, 19 May 2025 23:49:41 -0400 Subject: [PATCH 18/55] remove dropdown js used for tools --- js/tool-selector.js | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 js/tool-selector.js diff --git a/js/tool-selector.js b/js/tool-selector.js deleted file mode 100644 index ee918eac1..000000000 --- a/js/tool-selector.js +++ /dev/null @@ -1,22 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const selectWrapper = document.querySelector('.select-wrapper'); - const openArrow = document.querySelector('.selector-open'); - const closedArrow = document.querySelector('.selector-closed');; - - // Add event listeners - selectWrapper.addEventListener('click', (event) => { - selectWrapper.classList.toggle('active'); - openArrow.classList.toggle('active'); - closedArrow.classList.toggle('active'); - event.stopPropagation(); // prevent it from triggering document click - }); - - // Close on outside click - document.addEventListener('click', (event) => { - if (!selectWrapper.contains(event.target)) { - selectWrapper.classList.remove('active'); - openArrow.classList.remove('active'); - closedArrow.classList.add('active'); - } - }); -}); From 6c018e65abae68262de3ab791a74dc7e468f2775 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Wed, 21 May 2025 14:51:11 +0200 Subject: [PATCH 19/55] link fixes (#407) Co-authored-by: Ilaria Enache --- products/messaging/overview.md | 12 ++++++------ products/multigov/overview.md | 10 +++++----- products/queries/overview.md | 20 ++++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/products/messaging/overview.md b/products/messaging/overview.md index 59c889730..3bdc53f9e 100644 --- a/products/messaging/overview.md +++ b/products/messaging/overview.md @@ -32,28 +32,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps diff --git a/products/multigov/overview.md b/products/multigov/overview.md index 767376b66..cd7d02275 100644 --- a/products/multigov/overview.md +++ b/products/multigov/overview.md @@ -35,19 +35,19 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets - **Coordinated Protocol Upgrades Across Chains** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains - **Progressive Decentralization for Multichain DAOs** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub ## Next Steps diff --git a/products/queries/overview.md b/products/queries/overview.md index 1b0e41c79..a18ef3570 100644 --- a/products/queries/overview.md +++ b/products/queries/overview.md @@ -37,29 +37,29 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution - - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution + - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades - **Multichain Prediction Markets** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds - - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks ## Next Steps From 129ddc0c3dacf4482c9ea5ff60167a5282f09004 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Wed, 21 May 2025 16:42:39 +0200 Subject: [PATCH 20/55] Typescript SDK - Get Started page (#380) * sdk first draft * grammarly check * adding description * grammarly check * update snippets * update links * update snippets * updae introduction * update title and metadata * updates snippets to match new example * prettier * applies feedback per review. Next Steps is still TODO * updates conclusion and next steps * adds NTT Get Started to Next Steps * mention advanced implementations in the introduction * generalize for all types of users * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * changed admonitions to "example" type r/t styling and look --------- Co-authored-by: DAWN KELLY Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --- .../typescript-sdk/get-started/snippet-1.ts | 21 +++ .../typescript-sdk/get-started/snippet-2.ts | 32 ++++ .../get-started/terminal-01.html | 12 ++ tools/typescript-sdk/get-started.md | 177 ++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 .snippets/code/tools/typescript-sdk/get-started/snippet-1.ts create mode 100644 .snippets/code/tools/typescript-sdk/get-started/snippet-2.ts create mode 100644 .snippets/code/tools/typescript-sdk/get-started/terminal-01.html diff --git a/.snippets/code/tools/typescript-sdk/get-started/snippet-1.ts b/.snippets/code/tools/typescript-sdk/get-started/snippet-1.ts new file mode 100644 index 000000000..4703fc99c --- /dev/null +++ b/.snippets/code/tools/typescript-sdk/get-started/snippet-1.ts @@ -0,0 +1,21 @@ +import { wormhole } from '@wormhole-foundation/sdk'; +// Import specific platform modules for the chains you intend to use +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + // Determine the network: "Mainnet", "Testnet", or "Devnet" + const network = 'Testnet'; + + // Initialize the SDK with the chosen network and platform contexts + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); +} + +main().catch((e) => { + console.error('Error initializing Wormhole SDK', e); + process.exit(1); +}); diff --git a/.snippets/code/tools/typescript-sdk/get-started/snippet-2.ts b/.snippets/code/tools/typescript-sdk/get-started/snippet-2.ts new file mode 100644 index 000000000..1e5f79878 --- /dev/null +++ b/.snippets/code/tools/typescript-sdk/get-started/snippet-2.ts @@ -0,0 +1,32 @@ +import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + const network = 'Testnet'; + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); + + // Example: Get a chain ID and RPC for Solana + const solanaDevnetChain = wh.getChain('Solana'); + console.log( + `Chain ID for Solana Testnet: ${solanaDevnetChain.config.chainId}` + ); + console.log(`RPC for Solana Testnet: ${solanaDevnetChain.config.rpc}`); + + // Example: Get a chain ID for Sepolia (EVM Testnet) + const sepoliaChain = wh.getChain('Sepolia'); + console.log(`Chain ID for Sepolia: ${sepoliaChain.config.chainId}`); + console.log(`RPC for Sepolia: ${sepoliaChain.config.rpc}`); +} + +main().catch((e) => { + console.error( + 'Error initializing Wormhole SDK or fetching chain information:', + e + ); + process.exit(1); +}); diff --git a/.snippets/code/tools/typescript-sdk/get-started/terminal-01.html b/.snippets/code/tools/typescript-sdk/get-started/terminal-01.html new file mode 100644 index 000000000..d7d0455a6 --- /dev/null +++ b/.snippets/code/tools/typescript-sdk/get-started/terminal-01.html @@ -0,0 +1,12 @@ +
+ npx tsx src/main.ts + Initializing Wormhole SDK... + Wormhole SDK Initialized! + Chain ID for Solana Testnet: 1 + RPC for Solana Testnet: https://api.devnet.solana.com + Chain ID for Sepolia: 10002 + RPC for Sepolia: https://ethereum-sepolia.publicnode.com + +
\ No newline at end of file diff --git a/tools/typescript-sdk/get-started.md b/tools/typescript-sdk/get-started.md index e69de29bb..550a7490a 100644 --- a/tools/typescript-sdk/get-started.md +++ b/tools/typescript-sdk/get-started.md @@ -0,0 +1,177 @@ +--- +title: Get Started with the TypeScript SDK +description: Follow this guide to install the Wormhole TypeScript SDK, initialize a Wormhole instance, and add the platforms your integration supports. +categories: Typescript-SDK +--- + +# Get Started with the TypeScript SDK + +## Introduction + +The Wormhole TypeScript SDK provides a unified, type-safe interface for building cross-chain applications. It is a foundational toolkit that supports interaction with core Wormhole protocols, including Native Token Transfers, Token Bridge, CCTP, and Settlement, giving developers a consistent API across multiple chains. + +This guide helps you install the SDK, initialize a `Wormhole` instance to support your desired network and blockchain platforms, and return chain-specific information to verify successful initialization. + +If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: + + ```bash + npm install --save-dev tsx typescript @types/node + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +## Install the SDK + +To install the Wormhole TypeScript SDK, use the following command: + +```bash +npm install @wormhole-foundation/sdk +``` + +This package combines all the individual packages to make setup easier. + +You can choose to install a specific set of packages as needed. For example, to install EVM-specific utilities, you can run: + +```bash +npm install @wormhole-foundation/sdk-evm +``` + +??? example "Complete list of individually published packages" + + Platform-Specific Packages + + - `@wormhole-foundation/sdk-evm` + - `@wormhole-foundation/sdk-solana` + - `@wormhole-foundation/sdk-algorand` + - `@wormhole-foundation/sdk-aptos` + - `@wormhole-foundation/sdk-cosmwasm` + - `@wormhole-foundation/sdk-sui` + + --- + + Protocol-Specific Packages + + - Core Protocol + - `@wormhole-foundation/sdk-evm-core` + - `@wormhole-foundation/sdk-solana-core` + - `@wormhole-foundation/sdk-algorand-core` + - `@wormhole-foundation/sdk-aptos-core` + - `@wormhole-foundation/sdk-cosmwasm-core` + - `@wormhole-foundation/sdk-sui-core` + + - Token Bridge + - `@wormhole-foundation/sdk-evm-tokenbridge` + - `@wormhole-foundation/sdk-solana-tokenbridge` + - `@wormhole-foundation/sdk-algorand-tokenbridge` + - `@wormhole-foundation/sdk-aptos-tokenbridge` + - `@wormhole-foundation/sdk-cosmwasm-tokenbridge` + - `@wormhole-foundation/sdk-sui-tokenbridge` + + - CCTP + - `@wormhole-foundation/sdk-evm-cctp` + - `@wormhole-foundation/sdk-solana-cctp` + - `@wormhole-foundation/sdk-aptos-cctp` + - `@wormhole-foundation/sdk-sui-cctp` + + - Other Protocols + - `@wormhole-foundation/sdk-evm-portico` + - `@wormhole-foundation/sdk-evm-tbtc` + - `@wormhole-foundation/sdk-solana-tbtc` + + --- + + Utility Packages + + - `@wormhole-foundation/sdk-base` + - `@wormhole-foundation/sdk-definitions` + - `@wormhole-foundation/sdk-connect` + + +## Initialize the SDK + +You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. + +1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + +2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + --8<-- "code/tools/typescript-sdk/get-started/snippet-1.ts" + ``` + +## Fetch Chain Information + +Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. + +1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: + + ```ts title="src/main.ts" + --8<-- "code/tools/typescript-sdk/get-started/snippet-2.ts" + ``` + +2. Run the script with the following command, replacing `INSERT_FILE_NAME` with your file name: + + ```bash + npx tsx INSERT_FILE_NAME + ``` + + You will see terminal output similar to the following: + + --8<-- "code/tools/typescript-sdk/get-started/terminal-01.html" + +Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and initialized a `Wormhole` instance. Consider the following options to build on what you've accomplished. + +## Next Steps + +- [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) +- [Send a multichain message](TODO: get started messaging) +- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) +- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) From 50001c091b09baf8f8eecacccad16611effdfd7a Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Wed, 21 May 2025 16:48:36 +0200 Subject: [PATCH 21/55] Token Bridge - Get Started page (#382) * initial commit * create intro * add Prerequisites * project setup steps * update link * script to perform transaction * next steps section * grammarly check * add wormholescan link * Update products/token-bridge/get-started.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update wording * update metadata description * update introduction * focus intro on token bridge * update tone for guide * turn sections into steps * update link with todo * reduce time to 5 minutes * update next step description * Apply suggestions from code review Co-authored-by: Erin Shaben * Update .snippets/code/products/token-bridge/get-started/snippet-1.ts Co-authored-by: Erin Shaben * add keystore management note * add step for key management * specify networks * generalize prerequisites * add details to step * lower transfer amount * generalize function * adapt page to automatic transfers * update private key * update section introduction * update step * update step * remove item based on feedback * update env references * Update products/token-bridge/get-started.md Co-authored-by: Erin Shaben * update comment * update intro * add description to step * Update .snippets/code/products/token-bridge/get-started/snippet-1.ts Co-authored-by: Erin Shaben * update comments on snippets * update link * update metadata * llm check --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Erin Shaben --- .../token-bridge/get-started/snippet-1.ts | 70 ++++ .../token-bridge/get-started/snippet-2.ts | 58 +++ .../token-bridge/get-started/snippet-3.ts | 48 +++ .../token-bridge/get-started/snippet-4.html | 14 + llms-files/llms-multigov.txt | 51 +++ llms-files/llms-token-bridge.txt | 293 +++++++++++++++ llms-full.txt | 336 +++++++++++++++++- llms.txt | 4 +- products/token-bridge/get-started.md | 102 +++++- 9 files changed, 971 insertions(+), 5 deletions(-) create mode 100644 .snippets/code/products/token-bridge/get-started/snippet-1.ts create mode 100644 .snippets/code/products/token-bridge/get-started/snippet-2.ts create mode 100644 .snippets/code/products/token-bridge/get-started/snippet-3.ts create mode 100644 .snippets/code/products/token-bridge/get-started/snippet-4.html diff --git a/.snippets/code/products/token-bridge/get-started/snippet-1.ts b/.snippets/code/products/token-bridge/get-started/snippet-1.ts new file mode 100644 index 000000000..ff4f5d7e4 --- /dev/null +++ b/.snippets/code/products/token-bridge/get-started/snippet-1.ts @@ -0,0 +1,70 @@ +import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + isTokenId, + TokenId, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + +/** + * Get the number of decimals for the token on the source chain. + * This helps convert a user-friendly amount (e.g., '1') into raw units. + */ +export async function getTokenDecimals( + wh: Wormhole, + token: TokenId, + chain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : chain.config.nativeTokenDecimals; +} diff --git a/.snippets/code/products/token-bridge/get-started/snippet-2.ts b/.snippets/code/products/token-bridge/get-started/snippet-2.ts new file mode 100644 index 000000000..10e2e3c52 --- /dev/null +++ b/.snippets/code/products/token-bridge/get-started/snippet-2.ts @@ -0,0 +1,58 @@ +import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Solana and Sepolia on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Solana'); + const rcvChain = wh.getChain('Sepolia'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Solana', 'native'); + const amt = '0.1'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = false; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Solana + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Wait for the signed attestation from the Guardian network + console.log('Fetching Attestation'); + const timeout = 5 * 60 * 1000; // 5 minutes + await xfer.fetchAttestation(timeout); + + // Redeem the tokens on Sepolia + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, destTxids); + + process.exit(0); +})(); diff --git a/.snippets/code/products/token-bridge/get-started/snippet-3.ts b/.snippets/code/products/token-bridge/get-started/snippet-3.ts new file mode 100644 index 000000000..f4e3f3953 --- /dev/null +++ b/.snippets/code/products/token-bridge/get-started/snippet-3.ts @@ -0,0 +1,48 @@ +import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Avalanche and Celo on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Celo'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Avalanche', 'native'); + const amt = '0.2'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = true; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Avalanche Fuji + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + process.exit(0); +})(); diff --git a/.snippets/code/products/token-bridge/get-started/snippet-4.html b/.snippets/code/products/token-bridge/get-started/snippet-4.html new file mode 100644 index 000000000..a7706f0ee --- /dev/null +++ b/.snippets/code/products/token-bridge/get-started/snippet-4.html @@ -0,0 +1,14 @@ +
+ npx tsx transfer.ts + Starting Transfer + Started Transfer: ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB'] + + Getting Attestation + Retrying Wormholescan:GetVaaBytes, attempt 0/900 + Retrying Wormholescan:GetVaaBytes, attempt 1/900 + Retrying Wormholescan:GetVaaBytes, attempt 2/900 + + Completing Transfer + Completed Transfer: [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ] + +
\ No newline at end of file diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 06b6d67f3..4152c8c8f 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -18,6 +18,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md [type: other] @@ -616,6 +617,56 @@ The main components of MultiGov include: - **Governance token** - allows holders to participate in governance across all integrated chains --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/multigov/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Multigov +description: Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. +categories: MultiGov +--- + +# Get Started with Multigov + +## Introduction + +[MultiGov](/docs/products/multigov/overview/){target=\_blank} enables multichain governance using Wormhole messaging. With MultiGov, token holders can create proposals, vote, and execute decisions from any supported chain, eliminating the need to bridge assets or rely on a single governance hub. + +This page walks you through the MultiGov deployment flow—from requesting access with Tally to choosing a network and following the appropriate deployment guide. + +## Prerequisites + +Before deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL): + +- **EVM chains**: + - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\_blank} standard + - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting + +- **Solana**: + - Use an SPL token + - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\_blank} + +## Request Tally Access + +MultiGov integrations are coordinated through [Tally](https://www.tally.xyz/explore){target=\_blank}, a multichain governance platform that powers proposal creation, voting, and execution. + +To get started, fill out the integration [intake form](https://www.tally.xyz/get-started){target=\_blank}. The Tally team will review your application and contact you to discuss deployment and setup requirements. + +Once approved, review the deployment flow below to understand the integration process. Then, follow the appropriate deployment guide to integrate MultiGov with your governance token on EVM chains, Solana, or other supported networks. + +## Deployment Flow + +MultiGov deployments follow a similar structure on both EVM and Solana. This section provides a high-level overview of the end-to-end flow. Each step is explained in more detail in the platform-specific deployment guides linked [below](#next-steps). + +[timeline(wormhole-docs/.snippets/text/products/multigov/deployment-flow-timeline.json)] + +## Next Steps + +You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: + + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index ba36643a5..03822e939 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -16,6 +16,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md [type: other] ## Full content for each doc page @@ -351,6 +352,298 @@ Updating the metadata (such as the token image, name, or symbol) of a wrapped to To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Token Bridge +description: Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). +categories: Token-Bridge, Transfers +--- + +# Get Started with Token Bridge + +## Introduction + +Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. + + - **Manual transfer** – where you control each step + - **Automatic transfer** – where a relayer finalizes the transfer for you + +These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} + +This guide uses a Solana wallet with [devnet SOL](https://faucet.solana.com/){target=\_blank} and an EVM wallet with [Sepolia ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank} for the manual transfer example, and [Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir token-bridge + cd token-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `SOL_PRIVATE_KEY` and `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Transfer + +This section shows how to run manual and automatic token transfers using a shared project structure. You will define helper utilities once and reuse them across both flows. + +In the manual transfer, you initiate a transfer on Solana, wait for Guardian signatures, and redeem the tokens on Sepolia, giving you complete control over each step. In the automatic transfer, the relayer handles attestation and redemption, simplifying the process between EVM chains. + +1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed: + + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + isTokenId, + TokenId, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + +/** + * Get the number of decimals for the token on the source chain. + * This helps convert a user-friendly amount (e.g., '1') into raw units. + */ +export async function getTokenDecimals( + wh: Wormhole, + token: TokenId, + chain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : chain.config.nativeTokenDecimals; +} + + ``` + +2. In `transfer.ts`, add the script for your preferred transfer mode. The `automatic` flag controls transfer behavior passed to `tokenTransfer()`; set it to `false` for manual transfers and `true` for automatic transfers + + === "Manual Transfer" + + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Solana and Sepolia on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Solana'); + const rcvChain = wh.getChain('Sepolia'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Solana', 'native'); + const amt = '0.1'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = false; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Solana + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Wait for the signed attestation from the Guardian network + console.log('Fetching Attestation'); + const timeout = 5 * 60 * 1000; // 5 minutes + await xfer.fetchAttestation(timeout); + + // Redeem the tokens on Sepolia + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, destTxids); + + process.exit(0); +})(); + ``` + + === "Automatic Transfer" + + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Avalanche and Celo on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Celo'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Avalanche', 'native'); + const amt = '0.2'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = true; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Avalanche Fuji + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + process.exit(0); +})(); + ``` + + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx transfer.ts + ``` + + If successful, the expected output should be similar to this: + +
+npx tsx transfer.ts +Starting Transfer +Started Transfer: ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB'] + +Getting Attestation +Retrying Wormholescan:GetVaaBytes, attempt 0/900 +Retrying Wormholescan:GetVaaBytes, attempt 1/900 +Retrying Wormholescan:GetVaaBytes, attempt 2/900 + +Completing Transfer +Completed Transfer: [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ] + +
+ +To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a manual multichain token transfer, explore these guides to continue building: + + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. diff --git a/llms-full.txt b/llms-full.txt index 46fb3e6f7..9ebbef4a0 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -13562,7 +13562,52 @@ The main components of MultiGov include: Doc-Content: https://wormhole.com/docs/products/multigov/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with Multigov +description: Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. +categories: MultiGov +--- + +# Get Started with Multigov + +## Introduction + +[MultiGov](/docs/products/multigov/overview/){target=\_blank} enables multichain governance using Wormhole messaging. With MultiGov, token holders can create proposals, vote, and execute decisions from any supported chain, eliminating the need to bridge assets or rely on a single governance hub. + +This page walks you through the MultiGov deployment flow—from requesting access with Tally to choosing a network and following the appropriate deployment guide. + +## Prerequisites + +Before deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL): + +- **EVM chains**: + - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\_blank} standard + - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting + +- **Solana**: + - Use an SPL token + - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\_blank} + +## Request Tally Access + +MultiGov integrations are coordinated through [Tally](https://www.tally.xyz/explore){target=\_blank}, a multichain governance platform that powers proposal creation, voting, and execution. + +To get started, fill out the integration [intake form](https://www.tally.xyz/get-started){target=\_blank}. The Tally team will review your application and contact you to discuss deployment and setup requirements. + +Once approved, review the deployment flow below to understand the integration process. Then, follow the appropriate deployment guide to integrate MultiGov with your governance token on EVM chains, Solana, or other supported networks. + +## Deployment Flow + +MultiGov deployments follow a similar structure on both EVM and Solana. This section provides a high-level overview of the end-to-end flow. Each step is explained in more detail in the platform-specific deployment guides linked [below](#next-steps). + +[timeline(wormhole-docs/.snippets/text/products/multigov/deployment-flow-timeline.json)] + +## Next Steps + +You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: + + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ @@ -17692,7 +17737,294 @@ To request an update, contact Solscan via [support@solscan.io](mailto:support@so Doc-Content: https://wormhole.com/docs/products/token-bridge/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with Token Bridge +description: Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). +categories: Token-Bridge, Transfers +--- + +# Get Started with Token Bridge + +## Introduction + +Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. + + - **Manual transfer** – where you control each step + - **Automatic transfer** – where a relayer finalizes the transfer for you + +These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} + +This guide uses a Solana wallet with [devnet SOL](https://faucet.solana.com/){target=\_blank} and an EVM wallet with [Sepolia ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank} for the manual transfer example, and [Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir token-bridge + cd token-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `SOL_PRIVATE_KEY` and `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Transfer + +This section shows how to run manual and automatic token transfers using a shared project structure. You will define helper utilities once and reuse them across both flows. + +In the manual transfer, you initiate a transfer on Solana, wait for Guardian signatures, and redeem the tokens on Sepolia, giving you complete control over each step. In the automatic transfer, the relayer handles attestation and redemption, simplifying the process between EVM chains. + +1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed: + + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + isTokenId, + TokenId, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + +/** + * Get the number of decimals for the token on the source chain. + * This helps convert a user-friendly amount (e.g., '1') into raw units. + */ +export async function getTokenDecimals( + wh: Wormhole, + token: TokenId, + chain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : chain.config.nativeTokenDecimals; +} + + ``` + +2. In `transfer.ts`, add the script for your preferred transfer mode. The `automatic` flag controls transfer behavior passed to `tokenTransfer()`; set it to `false` for manual transfers and `true` for automatic transfers + + === "Manual Transfer" + + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Solana and Sepolia on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Solana'); + const rcvChain = wh.getChain('Sepolia'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Solana', 'native'); + const amt = '0.1'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = false; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Solana + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Wait for the signed attestation from the Guardian network + console.log('Fetching Attestation'); + const timeout = 5 * 60 * 1000; // 5 minutes + await xfer.fetchAttestation(timeout); + + // Redeem the tokens on Sepolia + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, destTxids); + + process.exit(0); +})(); + ``` + + === "Automatic Transfer" + + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; + +(async function () { + // Initialize Wormhole SDK for Avalanche and Celo on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); + + // Define the source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Celo'); + + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Avalanche', 'native'); + const amt = '0.2'; + + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); + + // Set to false to require manual approval steps + const automatic = true; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; + + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); + + // Initiate the transfer from Avalanche Fuji + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + process.exit(0); +})(); + ``` + + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx transfer.ts + ``` + + If successful, the expected output should be similar to this: + +
+npx tsx transfer.ts +Starting Transfer +Started Transfer: ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB'] + +Getting Attestation +Retrying Wormholescan:GetVaaBytes, attempt 0/900 +Retrying Wormholescan:GetVaaBytes, attempt 1/900 +Retrying Wormholescan:GetVaaBytes, attempt 2/900 + +Completing Transfer +Completed Transfer: [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ] + +
+ +To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a manual multichain token transfer, explore these guides to continue building: + + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/transfer-wrapped-assets/ diff --git a/llms.txt b/llms.txt index 81125d3c8..421b34a5f 100644 --- a/llms.txt +++ b/llms.txt @@ -53,7 +53,7 @@ - [Replace Outdated Signatures in VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/tutorials/replace-signatures.md): Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. - [MultiGov Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md): Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. - [MultiGov FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md): Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md): No description available. +- [Get Started with Multigov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md): Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. - [Deploy MultiGov on EVM Chains](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-evm.md): Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - [MultiGov Deployment to Solana](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/deploy-to-solana.md): Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. - [Upgrading MultiGov on EVM](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/guides/upgrade-evm.md): Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. @@ -100,7 +100,7 @@ - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): No description available. - [Token Bridge FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md): Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): No description available. +- [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md): No description available. - [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. diff --git a/products/token-bridge/get-started.md b/products/token-bridge/get-started.md index 30404ce4c..6dd291c91 100644 --- a/products/token-bridge/get-started.md +++ b/products/token-bridge/get-started.md @@ -1 +1,101 @@ -TODO \ No newline at end of file +--- +title: Get Started with Token Bridge +description: Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). +categories: Token-Bridge, Transfers +--- + +# Get Started with Token Bridge + +## Introduction + +Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. + + - **Manual transfer** – where you control each step + - **Automatic transfer** – where a relayer finalizes the transfer for you + +These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} + +This guide uses a Solana wallet with [devnet SOL](https://faucet.solana.com/){target=\_blank} and an EVM wallet with [Sepolia ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank} for the manual transfer example, and [Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir token-bridge + cd token-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `SOL_PRIVATE_KEY` and `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Transfer + +This section shows how to run manual and automatic token transfers using a shared project structure. You will define helper utilities once and reuse them across both flows. + +In the manual transfer, you initiate a transfer on Solana, wait for Guardian signatures, and redeem the tokens on Sepolia, giving you complete control over each step. In the automatic transfer, the relayer handles attestation and redemption, simplifying the process between EVM chains. + +1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed: + + ```ts title="helper.ts" + --8<-- "code/products/token-bridge/get-started/snippet-1.ts" + ``` + +2. In `transfer.ts`, add the script for your preferred transfer mode. The `automatic` flag controls transfer behavior passed to `tokenTransfer()`; set it to `false` for manual transfers and `true` for automatic transfers + + === "Manual Transfer" + + ```ts title="transfer.ts" + --8<-- "code/products/token-bridge/get-started/snippet-2.ts" + ``` + + === "Automatic Transfer" + + ```ts title="transfer.ts" + --8<-- "code/products/token-bridge/get-started/snippet-3.ts" + ``` + + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx transfer.ts + ``` + + If successful, the expected output should be similar to this: + + --8<-- "code/products/token-bridge/get-started/snippet-4.html" + +To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a manual multichain token transfer, explore these guides to continue building: + + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains \ No newline at end of file From b363adab49f28246f222f4c97a9533c30aa457ca Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Wed, 28 May 2025 19:54:55 +0200 Subject: [PATCH 22/55] Update Diagrams (#414) * update diagrams * rename images * rename diagrams --------- Co-authored-by: Ilaria Enache --- .../concepts/architecture/architecture-1.webp | Bin 0 -> 159554 bytes .../concepts/architecture/architecture-2.webp | Bin 0 -> 199862 bytes .../architecture/multigov-detailed.webp | Bin 392128 -> 0 bytes .../architecture/multigov-high-level.webp | Bin 278072 -> 0 bytes .../guides/solana/ntt-solana-guide-1.webp | Bin 0 -> 56390 bytes .../products/queries/overview/overview-1.webp | Bin 174606 -> 73790 bytes .../concepts/architecture/architecture-2.webp | Bin 111454 -> 64890 bytes products/multigov/concepts/architecture.md | 4 ++-- .../guides/deploy-to-solana.md | 5 +++++ 9 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 images/products/multigov/concepts/architecture/architecture-1.webp create mode 100644 images/products/multigov/concepts/architecture/architecture-2.webp delete mode 100644 images/products/multigov/concepts/architecture/multigov-detailed.webp delete mode 100644 images/products/multigov/concepts/architecture/multigov-high-level.webp create mode 100644 images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp diff --git a/images/products/multigov/concepts/architecture/architecture-1.webp b/images/products/multigov/concepts/architecture/architecture-1.webp new file mode 100644 index 0000000000000000000000000000000000000000..1dbd578a75577c9a7f699315fe04c1e1e1b82152 GIT binary patch literal 159554 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

7@93`V=D{=Y-YR83v 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

hU>M_TM$Jf3(a6KP}?xFVcg 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 ^4Z&$%v?)TJhQu0Ok#4~Mi&Qx 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 S-@8$xo}NMc5!*^`(EkC1ONDCy diff --git a/images/products/multigov/concepts/architecture/multigov-high-level.webp b/images/products/multigov/concepts/architecture/multigov-high-level.webp deleted file mode 100644 index f265146ca4d8975afc60f4f42a1fef856c4b5037..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278072 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 ~$5 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

w!_DY}&87vrmj{C5Ia+OH`aY+D(y{HLr>K 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%0A(PSAsk;VFn`S(y?r)jznb8;iUF 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 literal 174606 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 +$sb=nnk+ltgFynC;;Av3# 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�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 diff --git a/images/products/settlement/concepts/architecture/architecture-2.webp b/images/products/settlement/concepts/architecture/architecture-2.webp index b5f218b770510c34d5ce1e1318353c98fbf9d597..549337e96c5945766a638f1c3997f9ede56c0aaa 100644 GIT binary patch literal 64890 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∨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Μ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 diff --git a/products/multigov/concepts/architecture.md b/products/multigov/concepts/architecture.md index fdbbbc302..a28d63706 100644 --- a/products/multigov/concepts/architecture.md +++ b/products/multigov/concepts/architecture.md @@ -12,7 +12,7 @@ Wormhole’s multichain messaging infrastructure connects the hub and spokes, en The diagram below illustrates this high-level architecture. -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/architecture-1.webp) ## Key Components @@ -132,4 +132,4 @@ MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensu This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. -![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp) diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index 56333a44c..e9b056b41 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -10,8 +10,13 @@ categories: NTT, Transfer This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. + +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. + ## Prerequisites Before deploying NTT on Solana, ensure you have the following: From bff42177c001fb0897d268401ab6fa877c105e11 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Thu, 29 May 2025 07:44:43 +0200 Subject: [PATCH 23/55] Token Bridge Payload Structure (#422) * token bridge payloads * add summary table * grammarly check * Update products/token-bridge/concepts/payload-structure.md Co-authored-by: Erin Shaben * Update products/token-bridge/concepts/payload-structure.md Co-authored-by: Erin Shaben * apply feedback --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- .../concepts/payload-structure.md | 279 +++++++++++++++++- 1 file changed, 278 insertions(+), 1 deletion(-) diff --git a/products/token-bridge/concepts/payload-structure.md b/products/token-bridge/concepts/payload-structure.md index 30404ce4c..85b83c4aa 100644 --- a/products/token-bridge/concepts/payload-structure.md +++ b/products/token-bridge/concepts/payload-structure.md @@ -1 +1,278 @@ -TODO \ No newline at end of file +--- +title: Token Bridge Payload Structure +description: Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. +categories: Token-Bridge, Transfers +--- + +# Message and Payload Structure + +To enable secure and flexible cross-chain token transfers, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} defines a set of standardized payloads. These payloads are embedded in [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} and processed by bridge contracts on the source and destination chains. Each payload has a unique format and serves a specific role in the lifecycle of token bridging. + +This page outlines each payload type in detail. + +## Transfer + +The `Transfer` payload (ID = `1`) is the core mechanism for moving tokens across chains. It is emitted when a user locks or burns tokens on the source chain. On the destination chain, it instructs the bridge to either mint a wrapped token or release native tokens from custody. + +```text +PayloadID uint8 = 1 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +Fee uint256 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `1`, indicating a `Transfer` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals for consistency across all chains. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Left-zero-padded if shorter than 32 bytes. + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `Fee` ++"uint256"++ + + Amount of tokens that the user is willing to pay as relayer fee. Must be less than Amount. Optional and can be claimed by relayers who submit the VAA on the target chain. + + +To keep `Transfer` messages small, they don't carry all the token's metadata. However, this means that before a token can be transferred to a new chain for the first time, the metadata needs to be bridged, and the wrapped asset needs to be created. Metadata, in this case, includes the number of decimals, which is a core requirement for instantiating a token. + +## AssetMeta + +Before a token can be transferred to a new chain for the first time, its metadata must be attested using the `AssetMeta` payload (ID = `2`). This ensures proper decimal precision and display. + +```text +PayloadID uint8 = 2 +TokenAddress [32]uint8 +TokenChain uint16 +Decimals uint8 +Symbol [32]uint8 +Name [32]uint8 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `2`, indicating a `AssetMeta` operation. + + --- + + `TokenAddress` ++"[32]uint8"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `Decimals` ++"uint8"++ + + Number of decimals the token uses on its native chain (not truncated to 8). + + --- + + `Symbol` ++"[32]uint8"++ + + Symbol of the token, UTF-8 encoded and padded to 32 bytes. + + --- + + `Name` ++"[32]uint8"++ + + Name of the token, UTF-8 encoded and padded to 32 bytes. + +## TransferWithPayload + +The `TransferWithPayload` payload (ID = `3`) extends the standard token transfer by allowing developers to include arbitrary data. This enables interactions with destination chain smart contracts, such as triggering swaps or staking. + +```text +PayloadID uint8 = 3 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +FromAddress bytes32 +Payload bytes +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `3`, indicating a `TransferWithPayload` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `FromAddress` ++"bytes32"++ + + Address of the sender on the source chain. + + --- + + `Payload` ++"bytes"++ + + Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic. + + +Unlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly. + +## RegisterChain + +The `RegisterChain` governance payload (Action ID = `1`) registers a Token Bridge emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers. + +```text +Module [32]byte +Action uint8 = 1 +ChainId uint16 + +EmitterChainID uint16 +EmitterAddress [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier. Left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `1`, indicating a `RegisterChain` operation. + + --- + + `ChainID` ++"uint16"++ + + The chain where this governance action should be applied. `0` is a valid value for all chains + + --- + + `EmitterChainID` ++"uint16"++ + + Chain ID of the registered emitter. + + --- + + `EmitterAddress` ++"[32]uint8"++ + + Address of the registered emitter, left-zero-padded if shorter than 32 bytes. + +This payload can only be emitted by the Wormhole governance contract, ensuring that each chain accepts messages only from one verified bridge emitter per remote chain. + +## UpgradeContract + +The `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the Token Bridge contract on a specific chain. + +```text +Module [32]byte +Action uint8 = 2 +ChainId uint16 + +NewContract [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier, left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `2`, indicating an `UpgradeContract` operation. + + --- + + `ChainID` ++"uint16"++ + + The target chain where the governance action should be applied. + + --- + + `NewContract` ++"[32]uint8"++ + + Address of the new Token Bridge contract, left-zero-padded to 32 bytes. + +This message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security. + +## Summary of Payload Structure + +| Payload Type | ID | Purpose | Who Emits It | +|-----------------------|---------------|------------------------------------------------------------------------|------------------------| +| `Transfer` | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination | Token Bridge contract | +| `AssetMeta` | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer | Token Bridge contract | +| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution | Token Bridge contract | +| `RegisterChain` | Action `1` | Registers a verified Token Bridge emitter for a foreign chain | Wormhole governance | +| `UpgradeContract` | Action `2` | Upgrades the Token Bridge contract on a specific chain | Wormhole governance | \ No newline at end of file From 27797a013019c17fbd803839862ed7239aafbaa1 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Thu, 29 May 2025 07:55:39 +0200 Subject: [PATCH 24/55] Overview - Token Bridge (#410) * update sdk to the latest version (#374) * Add gitignore step (#372) * add instructions for including .gitignore when starting fresh projects * update llms --------- Co-authored-by: Martin Hofmann * update sdk to latest version (#386) * Added cctp-bridge overview.md (#393) * added cctp-bridge overview.md * Revisions/added timeline * fixed list issues * added links * fixed wording for use cases * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * revisions * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Erin Shaben --------- Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * revision * Issue check * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * revisions * Apply suggestions from code review Co-authored-by: Erin Shaben * revision/diagram * remove file * Update products/token-bridge/overview.md * Update products/token-bridge/overview.md * Update products/token-bridge/overview.md * Update products/token-bridge/overview.md * Update products/token-bridge/overview.md Co-authored-by: Erin Shaben * Update products/token-bridge/overview.md Co-authored-by: Erin Shaben * Update products/token-bridge/overview.md Co-authored-by: Erin Shaben * Update products/token-bridge/overview.md Co-authored-by: Erin Shaben * Update products/token-bridge/overview.md --------- Co-authored-by: Martin Hofmann Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Taylor Lucero Co-authored-by: Erin Shaben --- images/.DS_Store | Bin 6148 -> 0 bytes images/learn/.DS_Store | Bin 6148 -> 0 bytes llms-full.txt | 1478 +++++++++++++++++++++++++++++ products/token-bridge/overview.md | 80 +- 4 files changed, 1557 insertions(+), 1 deletion(-) delete mode 100644 images/.DS_Store delete mode 100644 images/learn/.DS_Store diff --git a/images/.DS_Store b/images/.DS_Store deleted file mode 100644 index 59ea4caf7193fab8d6aa2609047227a15e2a8f89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z>*NO(;SS3Oz1(E!tKo6fd#XgI6PZP^pOx8jQP=w&qX@IqM7gB)*Q$ z>~5t}y@^Pff!S{|JCkI;4Lcde81GGnEyik$F$WZ};KJ~Y;5_P*6s)HR$n`zsaiVU* zM1@PSn}ux+33;k^lSK-#G`Su`Nj*yQhBZ7 zRGg}F<=?5y9|z;fs28Lccy+2&63*=)Jd2}jP}?|Eava1mN_9d!j3DIlJeEV1_0&WT zM>^Lx6OQY+gIaw$ZFf5jvDa+P8e-aQH^JWR%x12$xwW%@GPqA3qOq9F@?>u83Nk|M31H`~;F>!4b|FVFz=EanEm142Inng$w(fj?#71FQE|UH||9 diff --git a/images/learn/.DS_Store b/images/learn/.DS_Store deleted file mode 100644 index 8ce67798e3403df9206e12b6c73e1b9035d01738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!EVz)5S>i}v6Uj_08);YdabBaP^5^93E|LdUBLlR8rKn6nB6FG$RUd4GyD)= z!tc;GyPFCW$}ytVj5PbkyYp=CTWi-tL~6Lqdqf=~3gC>55Y1nV$JuwR;d>5%%HG3J zPD{F?ii(|V>G&TN;I%u%YH6(5oPJ+FL;9>VS6OK?zKDKBS+_Dy=5faxt9D-|^LjF=e)mC)t}~x*B&LzcRX-6nZ+h zgd(3J<^9`2=VmoDOPwz)H+2I+7=+_acfCFx^pB(Gac^@Rtp}$u;%EKMCJde&oxC_7 ze=fgh^UcnH6uw()k34SSJAzwv`I^pkY4k_rZ24QBpeP^;hyr&(0l#+z?Yr=@@{Xc_ zD6m%rcz=lCjETqEq1`&r*b)HPM7K4>{Hw^E$YbKMc8C#}a#WzBDqmtKM@N6;^AeA> zLq{j&ix1_WtbB!{?9*}o$flD@97-z+hys5qz_lN&!{`6&+v|UuB#kH_3fxZxRCAP$ zhM1c_TX$y3XKe((gtKv8?eK + +- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Messaging Contracts** + + --- + + Learn how to build and deploy smart contracts that communicate seamlessly across multiple blockchains. This tutorial walks you through using Wormhole's Solidity SDK to send and receive messages between Avalanche Fuji and Celo Alfajores, helping you master emitter validation, relayer usage, and cross-chain cost management. + + [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-contracts/) + +- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Token Transfer Contracts** + + --- + + Discover how to create a fully functional cross-chain token transfer system using Wormhole's Solidity SDK. This tutorial guides you through token attestation, contract deployment, and secure transfers of ERC-20 tokens between test networks. By the end, you’ll know how to tap into global liquidity and enrich your dApps with seamless multi-chain asset movement. + + [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) + +

QnZi*%Um)?`bd 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 z%0A7z?XN~xDsQ#x`*wrYj1ahJn) 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%0A-B(w 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�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

+ +## Additional Resources + +
+ +- :octicons-book-16:{ .lg .middle } **Core Contracts** + + --- + + Dive deeper into Wormhole’s foundational concepts for cross-chain contracts. Discover how messaging, guardians, and VAAs work together to enable secure, scalable dApps. + + [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) + +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/ +--- BEGIN CONTENT --- +--- +title: Wormhole SDK Tutorials +description: Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. +--- + +# Wormhole SDK + +The Wormhole SDK provides the essential building blocks for creating robust cross-chain applications. With its developer-friendly libraries, tools, and interfaces, you can quickly integrate Wormhole’s messaging, token transfer, and governance functionalities into your projects. Whether you’re building a simple cross-chain dApp or architecting a complex multi-chain ecosystem, these tutorials will guide you through mastering the SDK and unlocking the full potential of Wormhole’s infrastructure. + +## Tutorials + +
+ +- :octicons-repo-16:{ .lg .middle } **Transfer USDC via CCTP** + + --- + + Learn how to move native USDC across chains using Circle’s CCTP and Wormhole’s TypeScript SDK. This tutorial shows you how to streamline transfers with automated attestation and finalization or take complete control with manual steps. Gain the skills to handle seamless USDC bridging, optimize user experience, and improve the reliability of your cross-chain applications. + + [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/usdc-via-cctp/) + +- :octicons-repo-16:{ .lg .middle } **Transfer Tokens via the Token Bridge** + + --- + + Learn how to build a versatile cross-chain token transfer application using Wormhole’s TypeScript SDK. This tutorial walks you through leveraging the Token Bridge to securely and efficiently move assets between EVM and non-EVM chains. By the end, you’ll understand how to transfer tokens between networks like Ethereum, Solana, Sui, and beyond, opening the door to an interconnected blockchain ecosystem. + + [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/) + +
+ +## Additional Resources + +
+ +- :octicons-tools-16:{ .lg .middle } **Wormhole SDK Documentation** + + --- + + Learn to build cross-chain dApps using the Wormhole SDK. Access detailed guides, reference code, and best practices for robust application development. + + [:custom-arrow: Learn more](/docs/build/toolkit/typescript-sdk/) + +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/tokens-via-token-bridge/ +--- BEGIN CONTENT --- +--- +title: Transfer Tokens via Token Bridge Tutorial +description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +--- + +# Transfer Tokens via the Token Bridge + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} + +## Introduction + +This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. + +By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: + + - EVM to EVM (e.g., Ethereum to Avalanche) + - EVM to non-EVM chains (e.g., Ethereum to Solana) + - Non-EVM to EVM chains (e.g., Sui to Avalanche) + - Non-EVM to non-EVM chains (e.g., Solana to Sui) + +Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. + +At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. + +## Prerequisites + +Before you begin, ensure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - Native tokens (testnet or mainnet) in Solana and Sui wallets + - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees + +## Supported Chains + +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. + +## Project Setup + +In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. + +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project + + ```bash + mkdir native-transfers + cd native-transfers + npm init -y + ``` + +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries + + ```bash + npm install @wormhole-foundation/sdk dotenv tsx + ``` + +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project + + ```bash + touch .env + ``` + + Inside the `.env` file, add your private keys. + + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" + ``` + + !!! note + Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. + +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays + + 1. Create the helpers file + + ```bash + mkdir -p src/helpers + touch src/helpers/helpers.ts + ``` + + 2. Open the `helpers.ts` file and add the following code + + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + TokenId, + isTokenId, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import { config } from 'dotenv'; +config(); + +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} + +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} + +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext, + gasLimit?: bigint +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + const evmSignerOptions = gasLimit ? { gasLimit } : {}; + signer = await ( + await evm() + ).getSigner( + await chain.getRpc(), + getEnv('ETH_PRIVATE_KEY'), + evmSignerOptions + ); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); + break; + case 'Aptos': + signer = await ( + await aptos() + ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + +export async function getTokenDecimals< + N extends 'Mainnet' | 'Testnet' | 'Devnet' +>( + wh: Wormhole, + token: TokenId, + sendChain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : sendChain.config.nativeTokenDecimals; +} + + ``` + + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file + - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers + +## Check and Create Wrapped Tokens + +Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. + +In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. + +### Configure the Wrapped Token Script + +1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory + + ```bash + mkdir -p src/scripts + touch src/scripts/create-wrapped.ts + ``` + +2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions + + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; + ``` + +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support + + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` + + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. + +4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) + + ```typescript + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); + ``` + +5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation + + ```typescript + + ``` + +6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation + + ```typescript + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } + ``` + + If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/#token-transfers). Otherwise, an attestation must be generated. + +7. **Set up the source chain signer** - the signer creates and submits the attestation transaction + + ```typescript + + ``` + +8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step + + ```typescript + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); + + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); + ``` + +9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure + + ```typescript + console.log('Parsed Messages:', msgs); + + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } + ``` + +10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation + + ```typescript + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); + + const tsx = await signSendWait(destChain, subAttestation, destSigner); + ``` + +11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain + + ```typescript + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } + + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` + + If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. + +??? code "Complete script" + ```typescript + import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; + +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Define the source and destination chains + const srcChain = wh.getChain('ArbitrumSepolia'); + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); + + // Destination chain signer setup + const { signer: destSigner } = await getSigner(destChain, gasLimit); + const tbDest = await destChain.getTokenBridge(); + + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } + + // Source chain signer setup + const { signer: origSigner } = await getSigner(srcChain); + + // Create an attestation transaction on the source chain + const tbOrig = await srcChain.getTokenBridge(); + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); + + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); + + // Retrieve the Wormhole message ID from the attestation transaction + const msgs = await srcChain.parseTransaction(txid); + console.log('Parsed Messages:', msgs); + + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } + + console.log('Token Address: ', vaa.payload.token.address); + + // Submit the attestation on the destination chain + console.log('Attesting asset on destination chain...'); + + const subAttestation = tbDest.submitAttestation( + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); + + const tsx = await signSendWait(destChain, subAttestation, destSigner); + console.log('Transaction hash: ', tsx); + + // Poll for the wrapped asset until it's available + async function waitForIt() { + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } + + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` + +### Run the Wrapped Token Creation + +Once the script is ready, execute it with: + +```bash +npx tsx src/scripts/create-wrapped.ts +``` + +If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. + +## Token Transfers + +In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. + +### Configure Transfer Details + +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. + +1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains + + ```bash + touch src/scripts/native-transfer.ts + ``` + +2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files + + ```typescript + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; + ``` + +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support + + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` + +4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them + + ```typescript + const rcvChain = wh.getChain('Solana'); + ``` + +5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains + + ```typescript + const destination = await getSigner(rcvChain); + ``` + +6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object + + ```typescript + + ``` + +7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit + + ```typescript + + ``` + +8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself + + ```typescript + + ``` + + !!! note + Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. + +9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function + + ```typescript + + ``` + +10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` + + ```typescript + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); + ``` + + Finally, we use `process.exit(0);` to close the script once the transfer completes + + ```typescript + })(); + ``` + +### Token Transfer Logic + +This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. + +#### Defining the Token Transfer Function + +The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. + +```typescript +wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic +import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; + +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); + + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); + + // Define the amount of tokens to transfer + const amt = '1'; + + // Set automatic transfer to false for manual transfer + const automatic = false; + + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); + + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); + + process.exit(0); +})(); + +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); + + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); + + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; + + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); + + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); + + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +} + +``` + +#### Steps to Transfer Tokens + +The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: + +1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step + + ```typescript + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); + ``` + +2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying + + ```typescript + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); + + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; + ``` + +3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process + + ```typescript + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + ``` + + - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} + + ???- note "How Cross-Chain Transfers Work in the Background" + When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: + + - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount + - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains + - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network + - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer + + This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. + +4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain + + ```typescript + + ``` + +5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer + + ```typescript + console.log(`Completed Transfer: `, destTxids); + ``` + +??? code "Complete script" + ```typescript + import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; + +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); + + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); + + // Define the amount of tokens to transfer + const amt = '1'; + + // Set automatic transfer to false for manual transfer + const automatic = false; + + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); + + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); + + process.exit(0); +})(); + +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); + + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); + + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; + + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); + + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); + + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +} + + ``` + +### Run the Native Token Transfer + +Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: + +```bash +npx tsx src/scripts/native-transfer.ts +``` + +This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). + +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Resources + +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. + +## Conclusion + +You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. + +The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/usdc-via-cctp/ +--- BEGIN CONTENT --- +--- +title: Transfer USDC via CCTP and Wormhole SDK +description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +--- + +# Transfer USDC via CCTP and Wormhole SDK + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} + +## Introduction + +In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. + +Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. + +Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. + +In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. + +## Core Concepts + +When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: + + - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain + + - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you + +## Prerequisites + +Before you begin, ensure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples + - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees + +## Supported Chains + +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. + +## Project Setup + +In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. + +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project + + ```bash + mkdir cctp-circle + cd cctp-circle + npm init -y + ``` + +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + + ```bash + echo ".env" >> .gitignore + ``` + +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries + + ```bash + npm install @wormhole-foundation/sdk dotenv + ``` + +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project + + ```bash + touch .env + ``` + + Inside the `.env` file, add your private key + + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + ``` + + !!! note + Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. + +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays + + 1. Create the helpers file + + ```bash + mkdir helpers + touch helpers/helpers.ts + ``` + + 2. Open the `helpers.ts` file and add the following code + + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { config } from 'dotenv'; +config(); + +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} + +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} + +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file + +6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains + + 1. Create the `manual-transfer.ts` file in the `src` directory + + ```bash + touch src/manual-transfer.ts + ``` + + 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files + + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; + ``` + + - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more + - **`solana`** - this adds support for Solana, a non-EVM chain + - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions + +## Manual Transfers + +In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. + +This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. + +### Set Up the Transfer Environment + +#### Configure Transfer Details + +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. + +1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed + + ```typescript + const wh = await wormhole('Testnet', [evm, solana]); + ``` + + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. + +2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them + + ```typescript + const rcvChain = wh.getChain('Sepolia'); + ``` + +3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains + + ```typescript + const destination = await getSigner(rcvChain); + ``` + +4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK + + ```typescript + + ``` + +5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself + + ```typescript + + ``` + +#### Initiate the Transfer + +To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. + +1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself + + ```typescript + amt, + source.address, + destination.address, + automatic + ); + ``` + +2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer + + ```typescript + console.log(`Started Transfer: `, srcTxids); + ``` + +#### Fetch the Circle Attestation (VAA) + +Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. + + +1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds + + ```typescript + + ``` + +2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout + + ```typescript + console.log(`Got Attestation: `, attestIds); + ``` + + The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain + +#### Complete the Transfer on the Destination Chain + +Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. + +Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain + +```typescript +console.log(`Completed Transfer: `, dstTxids); + + console.log('Circle Transfer status: ', xfer); + + process.exit(0); +``` + +The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed + +You can find the full code for the manual USDC transfer script below: + +???- code "`manual-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; + +(async function () { + const wh = await wormhole('Testnet', [evm, solana]); + + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; + + const automatic = false; + + // Create the Circle transfer object + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + console.log('Circle Transfer object created:', xfer); + + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Wait for Circle Attestation (VAA) + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); + + // Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); + + console.log('Circle Transfer status: ', xfer); + + process.exit(0); +})(); + ``` + +### Run Manual Transfer + +To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly + +```bash +npx ts-node src/manual-transfer.ts +``` + +This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). + +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. + +### Complete Partial Transfer + +In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. + +This feature is handy for recovering an incomplete transfer or when debugging. + +Here’s how you can complete a partial transfer using just the source chain and transaction hash: + +```typescript +wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); + + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); +``` + +You will need to provide the below requirements to complete the partial transfer: + +- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated +- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup + +This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. + +You can find the full code for the manual USDC transfer script below: + +??? code "`partial-transfer.ts`" + ```typescript + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); + + // Grab chain Contexts -- these hold a reference to a cached rpc client + const rcvChain = wh.getChain('Sepolia'); + + // Get signer from local key + const destination = await getSigner(rcvChain); + + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) + + // Rebuild the transfer from the source txid + const xfer = await CircleTransfer.from( + wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); + + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); + + console.log('Circle Transfer status: ', xfer); + + process.exit(0); +})(); + ``` + +## Automatic Transfers + +The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. + +### Set Up the Transfer Environment + +#### Configure Transfer Details + +The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you + +```typescript + +``` + +#### Initiate the Transfer + +The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain + +```typescript +amt, + source.address, + destination.address, + automatic + ); +``` + +#### Log Transfer Details + +After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer + +```typescript +console.log(`Started Transfer: `, srcTxids); + + process.exit(0); +``` + +You can find the full code for the automatic USDC transfer script below: + +??? code "`automatic-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); + + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000_001n; + + const automatic = true; + + // Create the Circle transfer object (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + console.log('Circle Transfer object created:', xfer); + + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + process.exit(0); +})(); + ``` + +### Run Automatic Transfer + +Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: + +```bash +npx ts-node src/automatic-transfer.ts +``` + +The automatic relayer will take care of fetching the attestation and completing the transfer for you. + +## Resources + +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. + +## Conclusion + +In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. + +By following these steps, you've learned how to: + +- Set up cross-chain transfers for native USDC between supported chains +- Handle both manual and automatic relaying of transactions +- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/ +--- BEGIN CONTENT --- +--- +title: Wormholescan API Tutorials +description: Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. +--- + +# Wormholescan API + +Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. + +## Tutorials + +
+ +- :octicons-repo-16:{ .lg .middle } **Replace Outdated Signatures in VAAs** + + --- + + Learn how to fetch VAAs, verify their validity, and replace outdated signatures using the Wormholescan API and Wormhole SDK. + + [:custom-arrow: Start tutorial](/docs/tutorials/wormholescan/replace-signatures/) + +
+ +## Additional Resources + +
+ +- :octicons-book-16:{ .lg .middle } **Wormholescan** + + --- + + Wormholescan is a blockchain explorer for tracking transactions, VAAs, and cross-chain activity. Its API provides programmatic access to transaction data, network analytics, and more. + + [:custom-arrow: Visit Wormholescan](https://wormholescan.io/){target=\_blank} + +
+--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/replace-signatures/ +======= Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ +>>>>>>> 50001c091b09baf8f8eecacccad16611effdfd7a --- BEGIN CONTENT --- --- title: Replace Outdated Signatures in VAAs diff --git a/products/token-bridge/overview.md b/products/token-bridge/overview.md index 30404ce4c..cbf2960ee 100644 --- a/products/token-bridge/overview.md +++ b/products/token-bridge/overview.md @@ -1 +1,79 @@ -TODO \ No newline at end of file +--- +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer +--- + +# Token Bridge Overview + +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. + +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. + +## Key Features + +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: + +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity + +## How It Works + +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: + +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain + +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. + +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana + + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message + + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) + + Solana->>Alice: Deliver wrapped ETH on Solana +``` + +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. + +## Use Cases + +Here are key use cases that highlight the power and versatility of the Token Bridge. + +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + +- **Tokenized Gaming Rewards** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + +- **Multichain DeFi Arbitrage** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + +## Next Steps + +If you are looking for more guided practice, take a look at: + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge \ No newline at end of file From 9d01cdab35afa41e0ad40dbd2c4cedb341210503 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Thu, 29 May 2025 15:10:28 +0200 Subject: [PATCH 25/55] CCTP - Get Started page (#408) * first commit * created cctp get started page * add metadata description * add file name to snippets * add next step * add metadata description * add usdc requirement * Update products/cctp-bridge/get-started.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/cctp-bridge/get-started.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * Update products/cctp-bridge/get-started.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/get-started.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/get-started.md Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Erin Shaben --- .../cctp-bridge/get-started/snippet-1.ts | 54 +++++++++++ .../cctp-bridge/get-started/snippet-2.ts | 56 ++++++++++++ .../cctp-bridge/get-started/snippet-3.html | 22 +++++ products/cctp-bridge/get-started.md | 89 ++++++++++++++++++- 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/products/cctp-bridge/get-started/snippet-1.ts create mode 100644 .snippets/code/products/cctp-bridge/get-started/snippet-2.ts create mode 100644 .snippets/code/products/cctp-bridge/get-started/snippet-3.html diff --git a/.snippets/code/products/cctp-bridge/get-started/snippet-1.ts b/.snippets/code/products/cctp-bridge/get-started/snippet-1.ts new file mode 100644 index 000000000..a7e6f99c9 --- /dev/null +++ b/.snippets/code/products/cctp-bridge/get-started/snippet-1.ts @@ -0,0 +1,54 @@ +import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} diff --git a/.snippets/code/products/cctp-bridge/get-started/snippet-2.ts b/.snippets/code/products/cctp-bridge/get-started/snippet-2.ts new file mode 100644 index 000000000..65017af41 --- /dev/null +++ b/.snippets/code/products/cctp-bridge/get-started/snippet-2.ts @@ -0,0 +1,56 @@ +import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helper'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Get signer from local key + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; + + const automatic = false; + + // Create the circleTransfer transaction (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + const quote = await CircleTransfer.quoteTransfer( + sendChain, + rcvChain, + xfer.transfer + ); + console.log('Quote: ', quote); + + // Step 1: Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Step 2: Wait for Circle Attestation (VAA) + const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); + + // Step 3: Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); + + process.exit(0); +})(); diff --git a/.snippets/code/products/cctp-bridge/get-started/snippet-3.html b/.snippets/code/products/cctp-bridge/get-started/snippet-3.html new file mode 100644 index 000000000..53983a1b3 --- /dev/null +++ b/.snippets/code/products/cctp-bridge/get-started/snippet-3.html @@ -0,0 +1,22 @@ +
+ npx tsx transfer.ts + Starting Transfer + Started Transfer: + [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', + '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] + + Waiting for Attestation + Retrying Circle:GetAttestation, attempt 0/60 + Retrying Circle:GetAttestation, attempt 1/60 + + Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] + + Completing Transfer + Completed Transfer: + [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] + +
diff --git a/products/cctp-bridge/get-started.md b/products/cctp-bridge/get-started.md index 30404ce4c..76efe23ae 100644 --- a/products/cctp-bridge/get-started.md +++ b/products/cctp-bridge/get-started.md @@ -1 +1,88 @@ -TODO \ No newline at end of file +--- +title: Get Started with CCTP +description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. +categories: Transfer +--- + +# Get Started with CCTP + +## Introduction + +[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. + +You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} + +This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir cctp-bridge + cd cctp-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a CCTP Transfer + +This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. + +Start by defining utility functions for signer and token setup: + +1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: + + ```ts title="helper.ts" + --8<-- "code/products/cctp-bridge/get-started/snippet-1.ts" + ``` + +2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: + + ```ts title="transfer.ts" + --8<-- "code/products/cctp-bridge/get-started/snippet-2.ts" + ``` + +3. Run the script to execute the transfer: + + ```bash + npx tsx transfer.ts + ``` + + You will see terminal output similar to the following: + + --8<-- "code/products/cctp-bridge/get-started/snippet-3.html" + +To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: + + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features \ No newline at end of file From ef9cba507790fd2242c54dc7696566c12485cccb Mon Sep 17 00:00:00 2001 From: Taylor Lucero Date: Thu, 29 May 2025 22:12:27 +0900 Subject: [PATCH 26/55] Overview - Connect (#412) * Added connect overview page. (#394) * added connect/overview.md * revisions/added timeline * remove checklist * updated timeline path * fix key features * fix key features * updated use cases * icon fix * timeline correction * update use cases * Update products/connect/overview.md * Update products/connect/overview.md * Apply suggestions from code review Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Erin Shaben * Apply suggestions from code review Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * revisions * revisions * revisions * Apply suggestions from code review Co-authored-by: Erin Shaben * Apply suggestions from code review Co-authored-by: Erin Shaben * some adjustments --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Erin Shaben Co-authored-by: Ilaria Enache --- .../connect/overview/connect-timeline.json | 17 +++++ products/connect/overview.md | 63 ++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 .snippets/text/products/reference/connect/overview/connect-timeline.json diff --git a/.snippets/text/products/reference/connect/overview/connect-timeline.json b/.snippets/text/products/reference/connect/overview/connect-timeline.json new file mode 100644 index 000000000..e429d9108 --- /dev/null +++ b/.snippets/text/products/reference/connect/overview/connect-timeline.json @@ -0,0 +1,17 @@ +[ + { + "title": "[Get Started with Connect](Todo)", + "content": "Integrate Connect into your React or JavaScript application with minimal setup.", + "icon": ":fontawesome-solid-1:" + }, + { + "title": "[Customize Transfer Logic](Todo)", + "content": "Configure supported chains, tokens, and transfer routes to fit your app's needs.", + "icon": ":fontawesome-solid-2:" + }, + { + "title": "[Customize the UI](Todo)", + "content": "Adapt Connect's interface to match your brand using flexible styling options.", + "icon": ":fontawesome-solid-3:" + } +] diff --git a/products/connect/overview.md b/products/connect/overview.md index 30404ce4c..50dc3c787 100644 --- a/products/connect/overview.md +++ b/products/connect/overview.md @@ -1 +1,62 @@ -TODO \ No newline at end of file +--- +title: Wormhole Connect +description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. +categories: Connect, Transfer +--- + +# Connect Overview + +With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. + +## Key Features + +Wormhole connect's notable features include: + +- **In-app multichain transfers**: Bridge assets without leaving your app. +- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. +- **Customizable UI**: Style the bridge interface to match your brand. +- **Optional destination gas**: Provide gas for initial transactions on the target chain. +- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. + +Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. + +## How It Works + +When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: + +1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. +2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). +3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. +6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. +7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. + +!!! tip + If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. + +## Use Cases + +Here are some key use cases that highlight the power and versatility of Connect: + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains + - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + +- **Cross-Chain Payment Widgets** + + - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + +- **Web3 Game Asset Transfers** + + - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + +## Next Steps + +Add Connect to your app with these key setup steps: + +[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] From bede78c1f17e44a8928a10cb571fffc1e6c8bae2 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Thu, 29 May 2025 09:25:24 -0400 Subject: [PATCH 27/55] add supported networks page (#431) --- .../queries/reference/supported-networks.md | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/products/queries/reference/supported-networks.md b/products/queries/reference/supported-networks.md index 30404ce4c..7954b4f83 100644 --- a/products/queries/reference/supported-networks.md +++ b/products/queries/reference/supported-networks.md @@ -1 +1,36 @@ -TODO \ No newline at end of file +--- +title: Queries Supported Networks +description: Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. +categories: Queries +--- + +# Supported Networks + +This page provides a quick reference for chains supported by Wormhole Queries, including each chain's Wormhole chain ID and the level of support for key methods: [`eth_call`](/docs/products/queries/reference/supported-methods/#eth_call){target=\_blank}, [`eth_call_by_timestamp`](/docs/products/queries/reference/supported-methods/#eth_call_by_timestamp){target=\_blank}, and [`eth_call_with_finality`](/docs/products/queries/reference/supported-methods/#eth_call_with_finality){target=\_blank}. + +The **Expected History** column shows how much recent state data is typically available for querying, though this can vary depending on the chain and the configuration of each Guardian node. + +The support shown in the table reflects what has been confirmed through testing. However, query success ultimately depends on whether the underlying call can be executed on each Guardian’s RPC node. + +For example, many chains use a fork of [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which by default retains 128 blocks of state in memory (unless archive mode is enabled). On Ethereum mainnet, this covers around 25 minutes of history—but on faster chains like Optimism, it may span only about three minutes. While Guardian nodes are expected to have access to recent state, there are currently no guarantees on how far back historical data is available. + +## Mainnet + +| Chain | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History | +|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:| +| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | +| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | +| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | +| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | +| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | +| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | +| Karura | 11 | ✅ | ✅ | ✅ | archive | +| Acala | 12 | ✅ | ✅ | ✅ | archive | +| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | +| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks | +| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks | +| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | +| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | +| Base | 30 | ✅ | ✅ | ✅ | archive | + +ℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. \ No newline at end of file From cc7c1dfd9e8c486898430dac60a56a43c6e39f69 Mon Sep 17 00:00:00 2001 From: Taylor Lucero Date: Thu, 29 May 2025 22:26:23 +0900 Subject: [PATCH 28/55] Taylor/supported methods (#428) * added supported methods * Grammarly fixes * nitpicking * Apply suggestions from code review Co-authored-by: Erin Shaben * revisions * meta update * Apply suggestions from code review Co-authored-by: Erin Shaben --------- Co-authored-by: Erin Shaben --- .../queries/reference/supported-methods.md | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/products/queries/reference/supported-methods.md b/products/queries/reference/supported-methods.md index 30404ce4c..83ee1720c 100644 --- a/products/queries/reference/supported-methods.md +++ b/products/queries/reference/supported-methods.md @@ -1 +1,55 @@ -TODO \ No newline at end of file +--- +title: Queries Supported Methods +description: Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. +categories: Queries +--- + +# Supported Methods + +Wormhole Queries provides on-demand access to [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}-attested on-chain data through a simple REST endpoint. It offers a faster, gasless alternative to traditional transaction-based data retrieval, removing the need for gas fees and transaction finality delays. Requests are handled off-chain and processed by the Guardians, delivering verified data efficiently and cost-effectively. + +This page describes Wormhole Queries, their functionality, and available methods, aiming to assist new developers in utilizing the service. + +## Supported Query Types + +Wormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains. + +!!! note + For a more comprehensive technical description and further specifics on each query type, please consult the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md). + + +### eth_call + +The [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} query type allows you to perform read-only calls to a smart contract on a specific block, identified by its number or hash. Some of eth_call's configurations include: + +- **Batching** - group multiple calls, even to different contracts, into a single query targeting the same block, which is processed as one batch RPC call to simplify on-chain verification +- **Capacity** - batch up to 255 individual in a single eth_call query +- **Result data** - provides the specified block's number, hash, timestamp, and the output from the contract call + +### eth_call_by_timestamp + +The [`eth_call_by_timestamp`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#timestamp-and-block-id-hints-in-eth_call_by_timestamp){target=\_blank} query is similar to a standard `eth_call` but targets a specific timestamp instead of a block ID. This is useful for retrieving on-chain data based on a precise point in time, especially for correlating information across different chains. + +The query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block. + +### eth_call_with_finality + +The [`eth_call_with_finality`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#desired-finality-in-eth_call_with_finality){target=\_blank} query type functions like a standard `eth_call`, but with an added critical assurance: it will only return the query results once the specified block has reached a designated level of finality on its chain. + +You can specify one of two finality levels for your query: + +- **Finalized** - indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain +- **Safe** - refers to a block considered highly unlikely to be reorganized, offering a substantial degree of confidence, though the network's consensus may not fully finalize it + +!!! note + If the target blockchain does not natively support or recognize the safe finality tag, requesting safe finality will be treated as a request for finalized finality instead. + +### sol_account + +The [`sol_account`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana-queries){target=\_blank} query reads on-chain data for one or more specified accounts on the Solana blockchain. This functionality is similar to using Solana's native [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} RPC method, enabling you to retrieve information for multiple accounts simultaneously + +### sol_pda + +The [`sol_pda`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana_queries){target=\_blank} query reads data for one or more Solana [Program Derived Addresses](https://www.anchor-lang.com/docs/pdas){target=\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data. + +This is particularly useful for accessing multiple PDAs owned by a specific program or for verifying Solana PDA derivations on another blockchain, such as how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. \ No newline at end of file From 37d1d79ca431cd84352ec4e6a45eec7062612b46 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Thu, 29 May 2025 09:26:50 -0400 Subject: [PATCH 29/55] Token Bridge Transfer Flow (#419) * add token bridge architecture overview * add flow of a transfer page * llms * update example and wording of native assets * clean up diagrams * Update products/token-bridge/concepts/transfer-flow.md Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --- llms-files/llms-token-bridge.txt | 181 +++++++++++++++- llms-files/llms-transfer.txt | 181 +++++++++++++++- llms-full.txt | 177 +++++++++++++++- llms.txt | 2 +- .../token-bridge/concepts/transfer-flow.md | 198 +++++++++++++++++- products/token-bridge/faqs.md | 10 +- 6 files changed, 726 insertions(+), 23 deletions(-) diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index 03822e939..c5f7a7911 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -15,6 +15,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md [type: other] @@ -312,6 +313,176 @@ The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardia A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ +--- BEGIN CONTENT --- +--- +title: Flow of a Token Bridge Transfer +description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. +categories: Token-Bridge, Transfer +--- + +# Flow of a Transfer + +## Introduction + +The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. + +This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. + +## Transfer Flow + +Cross-chain token transfers using the Token Bridge follow these steps: + +1. **Initiation on the Source Chain** + The transfer begins when a user calls the Token Bridge contract on the source chain: + + - **Wrapped tokens**: The token is burned. + - **Native tokens**: The token is locked in the contract. + +2. **Transfer Message Publication** + The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. + +3. **Message Observation and Signing** + [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. + + The VAA is then published to the Wormhole network. + +4. **VAA Submission to the Destination Chain** + The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: + + - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. + - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. + +5. **Finalization of the Transfer on the Destination Chain** + After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: + + - **Wrapped tokens**: A wrapped representation of the original token is minted. + - **Native tokens**: The original token is released to the recipient. + +```mermaid +sequenceDiagram + participant User + participant TokenBridgeSrc as Token Bridge
(Source Chain) + participant CoreSrc as Core Contract
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge
(Destination Chain) + participant CoreDst as Core Contract
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + TokenBridgeSrc->>CoreSrc: Publish message + CoreSrc-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeDst: Relayer submits VAA + else Manual VAA submission + User->>Guardians: Retrieve VAA + User->>TokenBridgeDst: User submits VAA directly + end + + TokenBridgeDst->>CoreDst: Verify VAA + CoreDst-->>TokenBridgeDst: VAA verified + TokenBridgeDst-->>User: Complete transfer (mint/release token) +``` + +## Automatic vs. Manual Transfers + +The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: + +- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. +- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. + +Here's a quick breakdown of the key differences: + +| Feature | Automatic Transfer | Manual Transfer | +|---------------------------|-----------------------------|-------------------------------------| +| Who submits the VAA? | Relayer | User or dApp | +| User Experience | Seamless, one-step | Requires manual intervention | +| Best for | End-users, simple UIs | Custom dApps, advanced control | +| Dependency | Requires relayer support | None | + +### Completing Manual Transfers + +The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. + +If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. + +## Token Bridge Relayer (TBR) + +When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. + + + +### Flow of an Automatic Transfer via TBR + +The flow of an automatic transfer using the TBR looks like this: + +1. **Initiation on the Source Chain** + The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + +2. **Prepare and Forward the Transfer** + The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. + +3. **Core Messaging Layer Processes the Transfer** + The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. + +4. **Off-Chain Relayer Observes the VAA** + + An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. + +5. **Relayer Computes Native Drop-Off and Submits the VAA** + + The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. + +6. **TBR Validates and Completes the Transfer** + + The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. + +6. **Asset Distribution on the Destination Chain** + + The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. + +The following diagram illustrates the key steps on the source chain during a transfer: + +```mermaid +sequenceDiagram + participant User + participant SourceTBR as Source Chain TBR + participant SourceTB as Source Chain Token Bridge + participant Messaging as Core Messaging Layer + + User->>SourceTBR: Initiate transfer (token,
recipient, fees, native gas) + SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) + SourceTB->>Messaging: Publish transfer message +``` + +Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: + +```mermaid +sequenceDiagram + participant Messaging as Core Messaging Layer + participant Relayer as Off-chain Relayer + participant DestTBR as Destination Chain TBR + participant DestTB as Destination Chain
Token Bridge + participant DestUser as User
(Destination Chain) + + Messaging->>Relayer: Emit signed VAA for transfer + Relayer->>Relayer: Verifies destination chain and token registration + Relayer->>DestTBR: Query native gas amount + Relayer->>DestTBR: Submit signed VAA + DestTBR->>DestTB: Validate VAA + DestTBR->>DestTBR: Take custody of tokens + DestTBR->>DestUser: Send tokens (after fees & native gas) + DestTBR->>Relayer: Pay relayer fee & refund excess +``` + +## Next Steps + +Now that you’ve seen how a transfer works try both types yourself to experience the full process: + +- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ --- BEGIN CONTENT --- --- @@ -320,9 +491,9 @@ description: Find answers to common questions about the Wormhole Token Bridge, i categories: Token-Bridge, Transfer --- -## FAQs +# FAQs -### Can ownership of wrapped tokens be transferred from the Token Bridge? +## Can ownership of wrapped tokens be transferred from the Token Bridge? No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. @@ -337,15 +508,15 @@ Relevant contracts: - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} -### How do I update the metadata of a wrapped token? +## How do I update the metadata of a wrapped token? Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. -### How can I update my wrapped token image on Solscan? +## How can I update my wrapped token image on Solscan? Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index 291e3d570..3d126e2fc 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -52,6 +52,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] ## Full content for each doc page @@ -7711,6 +7712,176 @@ This example solver does NOT do the following: - Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ +--- BEGIN CONTENT --- +--- +title: Flow of a Token Bridge Transfer +description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. +categories: Token-Bridge, Transfer +--- + +# Flow of a Transfer + +## Introduction + +The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. + +This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. + +## Transfer Flow + +Cross-chain token transfers using the Token Bridge follow these steps: + +1. **Initiation on the Source Chain** + The transfer begins when a user calls the Token Bridge contract on the source chain: + + - **Wrapped tokens**: The token is burned. + - **Native tokens**: The token is locked in the contract. + +2. **Transfer Message Publication** + The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. + +3. **Message Observation and Signing** + [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. + + The VAA is then published to the Wormhole network. + +4. **VAA Submission to the Destination Chain** + The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: + + - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. + - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. + +5. **Finalization of the Transfer on the Destination Chain** + After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: + + - **Wrapped tokens**: A wrapped representation of the original token is minted. + - **Native tokens**: The original token is released to the recipient. + +```mermaid +sequenceDiagram + participant User + participant TokenBridgeSrc as Token Bridge
(Source Chain) + participant CoreSrc as Core Contract
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge
(Destination Chain) + participant CoreDst as Core Contract
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + TokenBridgeSrc->>CoreSrc: Publish message + CoreSrc-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeDst: Relayer submits VAA + else Manual VAA submission + User->>Guardians: Retrieve VAA + User->>TokenBridgeDst: User submits VAA directly + end + + TokenBridgeDst->>CoreDst: Verify VAA + CoreDst-->>TokenBridgeDst: VAA verified + TokenBridgeDst-->>User: Complete transfer (mint/release token) +``` + +## Automatic vs. Manual Transfers + +The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: + +- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. +- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. + +Here's a quick breakdown of the key differences: + +| Feature | Automatic Transfer | Manual Transfer | +|---------------------------|-----------------------------|-------------------------------------| +| Who submits the VAA? | Relayer | User or dApp | +| User Experience | Seamless, one-step | Requires manual intervention | +| Best for | End-users, simple UIs | Custom dApps, advanced control | +| Dependency | Requires relayer support | None | + +### Completing Manual Transfers + +The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. + +If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. + +## Token Bridge Relayer (TBR) + +When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. + + + +### Flow of an Automatic Transfer via TBR + +The flow of an automatic transfer using the TBR looks like this: + +1. **Initiation on the Source Chain** + The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + +2. **Prepare and Forward the Transfer** + The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. + +3. **Core Messaging Layer Processes the Transfer** + The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. + +4. **Off-Chain Relayer Observes the VAA** + + An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. + +5. **Relayer Computes Native Drop-Off and Submits the VAA** + + The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. + +6. **TBR Validates and Completes the Transfer** + + The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. + +6. **Asset Distribution on the Destination Chain** + + The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. + +The following diagram illustrates the key steps on the source chain during a transfer: + +```mermaid +sequenceDiagram + participant User + participant SourceTBR as Source Chain TBR + participant SourceTB as Source Chain Token Bridge + participant Messaging as Core Messaging Layer + + User->>SourceTBR: Initiate transfer (token,
recipient, fees, native gas) + SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) + SourceTB->>Messaging: Publish transfer message +``` + +Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: + +```mermaid +sequenceDiagram + participant Messaging as Core Messaging Layer + participant Relayer as Off-chain Relayer + participant DestTBR as Destination Chain TBR + participant DestTB as Destination Chain
Token Bridge + participant DestUser as User
(Destination Chain) + + Messaging->>Relayer: Emit signed VAA for transfer + Relayer->>Relayer: Verifies destination chain and token registration + Relayer->>DestTBR: Query native gas amount + Relayer->>DestTBR: Submit signed VAA + DestTBR->>DestTB: Validate VAA + DestTBR->>DestTBR: Take custody of tokens + DestTBR->>DestUser: Send tokens (after fees & native gas) + DestTBR->>Relayer: Pay relayer fee & refund excess +``` + +## Next Steps + +Now that you’ve seen how a transfer works try both types yourself to experience the full process: + +- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ --- BEGIN CONTENT --- --- @@ -7719,9 +7890,9 @@ description: Find answers to common questions about the Wormhole Token Bridge, i categories: Token-Bridge, Transfer --- -## FAQs +# FAQs -### Can ownership of wrapped tokens be transferred from the Token Bridge? +## Can ownership of wrapped tokens be transferred from the Token Bridge? No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. @@ -7736,15 +7907,15 @@ Relevant contracts: - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} -### How do I update the metadata of a wrapped token? +## How do I update the metadata of a wrapped token? Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. -### How can I update my wrapped token image on Solscan? +## How can I update my wrapped token image on Solscan? Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. diff --git a/llms-full.txt b/llms-full.txt index 4923e6a28..f80189007 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -19170,7 +19170,172 @@ TODO Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ --- BEGIN CONTENT --- -TODO +--- +title: Flow of a Token Bridge Transfer +description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. +categories: Token-Bridge, Transfer +--- + +# Flow of a Transfer + +## Introduction + +The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. + +This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. + +## Transfer Flow + +Cross-chain token transfers using the Token Bridge follow these steps: + +1. **Initiation on the Source Chain** + The transfer begins when a user calls the Token Bridge contract on the source chain: + + - **Wrapped tokens**: The token is burned. + - **Native tokens**: The token is locked in the contract. + +2. **Transfer Message Publication** + The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. + +3. **Message Observation and Signing** + [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. + + The VAA is then published to the Wormhole network. + +4. **VAA Submission to the Destination Chain** + The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: + + - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. + - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. + +5. **Finalization of the Transfer on the Destination Chain** + After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: + + - **Wrapped tokens**: A wrapped representation of the original token is minted. + - **Native tokens**: The original token is released to the recipient. + +```mermaid +sequenceDiagram + participant User + participant TokenBridgeSrc as Token Bridge
(Source Chain) + participant CoreSrc as Core Contract
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge
(Destination Chain) + participant CoreDst as Core Contract
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + TokenBridgeSrc->>CoreSrc: Publish message + CoreSrc-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeDst: Relayer submits VAA + else Manual VAA submission + User->>Guardians: Retrieve VAA + User->>TokenBridgeDst: User submits VAA directly + end + + TokenBridgeDst->>CoreDst: Verify VAA + CoreDst-->>TokenBridgeDst: VAA verified + TokenBridgeDst-->>User: Complete transfer (mint/release token) +``` + +## Automatic vs. Manual Transfers + +The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: + +- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. +- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. + +Here's a quick breakdown of the key differences: + +| Feature | Automatic Transfer | Manual Transfer | +|---------------------------|-----------------------------|-------------------------------------| +| Who submits the VAA? | Relayer | User or dApp | +| User Experience | Seamless, one-step | Requires manual intervention | +| Best for | End-users, simple UIs | Custom dApps, advanced control | +| Dependency | Requires relayer support | None | + +### Completing Manual Transfers + +The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. + +If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. + +## Token Bridge Relayer (TBR) + +When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. + + + +### Flow of an Automatic Transfer via TBR + +The flow of an automatic transfer using the TBR looks like this: + +1. **Initiation on the Source Chain** + The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + +2. **Prepare and Forward the Transfer** + The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. + +3. **Core Messaging Layer Processes the Transfer** + The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. + +4. **Off-Chain Relayer Observes the VAA** + + An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. + +5. **Relayer Computes Native Drop-Off and Submits the VAA** + + The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. + +6. **TBR Validates and Completes the Transfer** + + The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. + +6. **Asset Distribution on the Destination Chain** + + The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. + +The following diagram illustrates the key steps on the source chain during a transfer: + +```mermaid +sequenceDiagram + participant User + participant SourceTBR as Source Chain TBR + participant SourceTB as Source Chain Token Bridge + participant Messaging as Core Messaging Layer + + User->>SourceTBR: Initiate transfer (token,
recipient, fees, native gas) + SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) + SourceTB->>Messaging: Publish transfer message +``` + +Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: + +```mermaid +sequenceDiagram + participant Messaging as Core Messaging Layer + participant Relayer as Off-chain Relayer + participant DestTBR as Destination Chain TBR + participant DestTB as Destination Chain
Token Bridge + participant DestUser as User
(Destination Chain) + + Messaging->>Relayer: Emit signed VAA for transfer + Relayer->>Relayer: Verifies destination chain and token registration + Relayer->>DestTBR: Query native gas amount + Relayer->>DestTBR: Submit signed VAA + DestTBR->>DestTB: Validate VAA + DestTBR->>DestTBR: Take custody of tokens + DestTBR->>DestUser: Send tokens (after fees & native gas) + DestTBR->>Relayer: Pay relayer fee & refund excess +``` + +## Next Steps + +Now that you’ve seen how a transfer works try both types yourself to experience the full process: + +- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ @@ -19181,9 +19346,9 @@ description: Find answers to common questions about the Wormhole Token Bridge, i categories: Token-Bridge, Transfer --- -## FAQs +# FAQs -### Can ownership of wrapped tokens be transferred from the Token Bridge? +## Can ownership of wrapped tokens be transferred from the Token Bridge? No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. @@ -19198,15 +19363,15 @@ Relevant contracts: - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} -### How do I update the metadata of a wrapped token? +## How do I update the metadata of a wrapped token? Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. -### How can I update my wrapped token image on Solscan? +## How can I update my wrapped token image on Solscan? Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. diff --git a/llms.txt b/llms.txt index 421b34a5f..c2878ccaa 100644 --- a/llms.txt +++ b/llms.txt @@ -98,7 +98,7 @@ - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md): No description available. - [Wormhole Settlements](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/tutorials/.settlement-routes.md): Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): No description available. +- [Flow of a Token Bridge Transfer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. - [Token Bridge FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md): Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. - [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md): No description available. diff --git a/products/token-bridge/concepts/transfer-flow.md b/products/token-bridge/concepts/transfer-flow.md index 30404ce4c..5ce1b9966 100644 --- a/products/token-bridge/concepts/transfer-flow.md +++ b/products/token-bridge/concepts/transfer-flow.md @@ -1 +1,197 @@ -TODO \ No newline at end of file +--- +title: Flow of a Token Bridge Transfer +description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. +categories: Token-Bridge, Transfer +--- + +# Flow of a Transfer + +## Introduction + +The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. + +This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. + +## Transfer Flow + +Cross-chain token transfers using the Token Bridge follow these steps: + +1. **Initiation on the Source Chain** + The transfer begins when a user calls the Token Bridge contract on the source chain: + + - **Wrapped tokens**: The token is burned. + - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. + +2. **Transfer Message Publication** + The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. + +3. **Message Observation and Signing** + [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. + + The VAA is then published to the Wormhole network. + +4. **VAA Submission to the Destination Chain** + The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: + + - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. + - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. + +5. **Finalization of the Transfer on the Destination Chain** + After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: + + - **Wrapped tokens**: A wrapped representation of the original token is minted. + - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. + +Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. + +```mermaid +sequenceDiagram + participant Alice as Alice + participant TokenBridgeEth as Token Bridge Ethereum
(Source Chain) + participant CoreEth as Core Contract Ethereum
(Source Chain) + participant Guardians + participant TokenBridgeSol as Token Bridge Solana
(Destination Chain) + participant CoreSol as Core Contract Solana
(Destination Chain) + + Alice->>TokenBridgeEth: Initiate ETH transfer
(lock ETH) + TokenBridgeEth->>CoreEth: Publish transfer message + CoreEth-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeSol: Relayer submits VAA + else Manual VAA submission + Alice->>Guardians: Retrieve VAA + Alice->>TokenBridgeSol: Submit VAA + end + + TokenBridgeSol->>CoreSol: Verify VAA + CoreSol-->>TokenBridgeSol: VAA verified + TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +``` + +Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. + +```mermaid +sequenceDiagram + participant User as Alice + participant TokenBridgeSrc as Token Bridge Solana
(Source Chain) + participant CoreSrc as Core Contract Solana
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge Ethereum
(Destination Chain) + participant CoreDst as Core Contract Ethereum
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn wrapped ETH) + TokenBridgeSrc->>CoreSrc: Publish message + CoreSrc-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeDst: Relayer submits VAA + else Manual VAA submission + User->>Guardians: Retrieve VAA + User->>TokenBridgeDst: User submits VAA directly + end + + TokenBridgeDst->>CoreDst: Verify VAA + CoreDst-->>TokenBridgeDst: VAA verified + TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) +``` + + +## Automatic vs. Manual Transfers + +The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: + +- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. +- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. + +Here's a quick breakdown of the key differences: + +| Feature | Automatic Transfer | Manual Transfer | +|---------------------------|-----------------------------|-------------------------------------| +| Who submits the VAA? | Relayer | User or dApp | +| User Experience | Seamless, one-step | Requires manual intervention | +| Best for | End-users, simple UIs | Custom dApps, advanced control | +| Dependency | Requires relayer support | None | + +### Completing Manual Transfers + +The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. + +If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. + +## Token Bridge Relayer (TBR) + +When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. + + + +### Flow of an Automatic Transfer via TBR + +The flow of an automatic transfer using the TBR looks like this: + +1. **Initiation on the Source Chain** + The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + +2. **Prepare and Forward the Transfer** + The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. + +3. **Core Messaging Layer Processes the Transfer** + The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. + +4. **Off-Chain Relayer Observes the VAA** + + An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. + +5. **Relayer Computes Native Drop-Off and Submits the VAA** + + The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. + +6. **TBR Validates and Completes the Transfer** + + The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. + +6. **Asset Distribution on the Destination Chain** + + The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. + +The following diagram illustrates the key steps on the source chain during a transfer: + +```mermaid +sequenceDiagram + participant User + participant SourceTBR as Source Chain TBR + participant SourceTB as Source Chain Token Bridge + participant Messaging as Core Messaging Layer + + User->>SourceTBR: Initiate transfer (token,
recipient, fees, native gas) + SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) + SourceTB->>Messaging: Publish transfer message +``` + +Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: + +```mermaid +sequenceDiagram + participant Messaging as Core Messaging Layer + participant Relayer as Off-chain Relayer + participant DestTBR as Destination Chain TBR + participant DestTB as Destination Chain
Token Bridge + participant DestUser as User
(Destination Chain) + + Messaging->>Relayer: Emit signed VAA for transfer + Relayer->>Relayer: Verifies destination chain and token registration + Relayer->>DestTBR: Query native gas amount + Relayer->>DestTBR: Submit signed VAA + DestTBR->>DestTB: Validate VAA + DestTBR->>DestTBR: Take custody of tokens + DestTBR->>DestUser: Send tokens (after fees & native gas) + DestTBR->>Relayer: Pay relayer fee & refund excess +``` + +## Next Steps + +Now that you’ve seen how a transfer works try both types yourself to experience the full process: + +- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} \ No newline at end of file diff --git a/products/token-bridge/faqs.md b/products/token-bridge/faqs.md index d860914f8..6497ea9d9 100644 --- a/products/token-bridge/faqs.md +++ b/products/token-bridge/faqs.md @@ -4,9 +4,9 @@ description: Find answers to common questions about the Wormhole Token Bridge, i categories: Token-Bridge, Transfer --- -## FAQs +# FAQs -### Can ownership of wrapped tokens be transferred from the Token Bridge? +## Can ownership of wrapped tokens be transferred from the Token Bridge? No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. @@ -21,15 +21,15 @@ Relevant contracts: - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} -### How do I update the metadata of a wrapped token? +## How do I update the metadata of a wrapped token? Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. -### How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. -### How can I update my wrapped token image on Solscan? +## How can I update my wrapped token image on Solscan? Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. From b096f7adb2ee4f6342af39385c1fd0fcc9029ffa Mon Sep 17 00:00:00 2001 From: Taylor Lucero Date: Thu, 29 May 2025 22:27:37 +0900 Subject: [PATCH 30/55] Overview - Native Token Tranfers (#413) * Added native-token-transfers/overview.md (#395) * added native-token-transfers/overview.md * staging * revision/added timeline * Revision * revisions/key feature fix/Supported token fix * update paths to overview pages * fix timeline * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --------- Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * Revisions * Apply suggestions from code review Co-authored-by: Erin Shaben * revisions * added to features * Apply suggestions from code review Co-authored-by: Erin Shaben * revisions * adjustments to token strandards section * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben --------- Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Ilaria Enache --- .../reference/ntt/overview/ntt-timeline.json | 17 ++++ products/native-token-transfers/overview.md | 80 ++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 .snippets/text/products/reference/ntt/overview/ntt-timeline.json diff --git a/.snippets/text/products/reference/ntt/overview/ntt-timeline.json b/.snippets/text/products/reference/ntt/overview/ntt-timeline.json new file mode 100644 index 000000000..6eb6d9a77 --- /dev/null +++ b/.snippets/text/products/reference/ntt/overview/ntt-timeline.json @@ -0,0 +1,17 @@ +[ + { + "title": "[Get Started with NTT](/docs/products/native-token-transfers/get-started/)", + "content": "Start your journey with Wormhole's NTT by learning to install its CLI, deploy test tokens, and set up it's initial structure for seamless token movement.", + "icon": ":fontawesome-solid-1:" + }, + { + "title": "Deploy NTT", + "content": "Use these resources to deploy NTT across supported chains:

**→** [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/) \n\n**→** [Deploy to EVM Chains via Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/) \n**→** [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/)", + "icon": ":fontawesome-solid-2:" + }, + { + "title": "Customize NTT", + "content": "Configure crucial operational and security settings for NTT:

**→** [Access control](/docs/products/native-token-transfers/configuration/access-control/) \n**→** [Rate limits](/docs/products/native-token-transfers/configuration/rate-limiting/)", + "icon": ":fontawesome-solid-3:" + } +] \ No newline at end of file diff --git a/products/native-token-transfers/overview.md b/products/native-token-transfers/overview.md index 30404ce4c..059df7372 100644 --- a/products/native-token-transfers/overview.md +++ b/products/native-token-transfers/overview.md @@ -1 +1,79 @@ -TODO \ No newline at end of file +--- +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer +--- + +## Native Token Transfers Overview + +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. + +## Key Features + +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps + + +## Deployment Models + +NTT offers two operational modes for your existing tokens: + +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token + +## Supported Token Standards + +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. + +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. + +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. + +## Deployment Process + +Here's a breakdown of the key steps involved when deploying NTT: + +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed + +## Use Cases + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + +- **Borrowing and Lending Across Chains** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + +- **Gas Abstraction** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + +- **Cross-Chain Payment Widgets** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + +- **Cross-Chain Staking** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + +## Next Steps + +Follow these steps to get started with NTT: + +[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] \ No newline at end of file From b3fd70a74e01cb5029db6f27a6a7b074d1d23830 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Thu, 29 May 2025 15:46:54 +0200 Subject: [PATCH 31/55] Overview - Settlement (#420) * link fix * metadata * settlement overview page * add table * mermaid diagrams updates * diagrams and explanations * next steps * Update products/settlement/overview.md Co-authored-by: Erin Shaben * applied feedback * remove liquidity layer diagram * Update products/settlement/overview.md Co-authored-by: Erin Shaben * apply feedback * Apply suggestions from code review Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- products/settlement/guides/.pages | 2 +- products/settlement/overview.md | 113 +++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/products/settlement/guides/.pages b/products/settlement/guides/.pages index 96019210a..8569cf10a 100644 --- a/products/settlement/guides/.pages +++ b/products/settlement/guides/.pages @@ -1,4 +1,4 @@ title: Guides nav: - 'Build on the Liquidity Layer': 'liquidity-layer.md' -- 'Run a Solver': 'run-a-solver.md' +- 'Run a Solver': 'solver.md' diff --git a/products/settlement/overview.md b/products/settlement/overview.md index 30404ce4c..9ff6d0553 100644 --- a/products/settlement/overview.md +++ b/products/settlement/overview.md @@ -1 +1,112 @@ -TODO \ No newline at end of file +--- +title: Settlement Overview +description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. +categories: Settlement, Transfer +--- + +# Settlement Overview + +Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. + +Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. + +It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. + +## Key Features + +- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. +- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. +- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. +- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. + +## How It Works + +At the core of Settlement are two components: + +- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. +- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. + +Settlement leverages the following three integrated protocols. + +### Mayan Swift + +Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. + +The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. + +1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. +2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. +3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. + +```mermaid +sequenceDiagram + participant User + participant Solver_ARB as Solver (Arbitrum) + participant Escrow + participant Wormhole + participant Solver_SOL as Solver (Solana) + participant Aggregator + + Note over User,Aggregator: User has ARB and wants WIF + + User->>Solver_ARB: Submit intent (ARB → WIF) + Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH + Escrow-->>Wormhole: Emits VAA + Wormhole-->>Solver_SOL: Delivers VAA + Solver_SOL->>Aggregator: Releases SOL and swaps to WIF + Aggregator->>Solver_SOL: Receives WIF + Solver_SOL->>User: Sends WIF + User-->>Wormhole: Emits final VAA + Wormhole-->>Escrow: Confirms receipt + Escrow->>Solver_ARB: Releases ETH to solver +``` + +### Liquidity Layer + +The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. + +### Mayan MCTP + +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. + +### One Integration, Three Ways + +Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. + +By default, Settlement integrates all three: + +- The SDK automatically resolves the best route for each transfer. +- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. +- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. + +Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. + +To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. + +## Use Cases + +- **Cross-Chain Perpetuals** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + +- **Bridging Intent Library** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + +- **Multichain Prediction Markets** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + +## Next Steps + +Start building with Settlement or dive deeper into specific components: + +- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. +- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. + From 0f0325b4b4c518598bfc8cf3df1d865d1fb684d5 Mon Sep 17 00:00:00 2001 From: Taylor Lucero Date: Fri, 30 May 2025 02:03:22 +0900 Subject: [PATCH 32/55] Overview - CCTP bridge (#411) * Added cctp-bridge overview.md (#393) * added cctp-bridge overview.md * Revisions/added timeline * fixed list issues * added links * fixed wording for use cases * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * revisions * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Erin Shaben --------- Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * list/revision/added key features * Update products/cctp-bridge/overview.md Co-authored-by: Erin Shaben * image pos * added image * update diagram * update diagram * Apply suggestions from code review Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * revisions * revisions * Remove .DS_Store files from repository * remove image * Apply suggestions from code review Co-authored-by: Erin Shaben * revisions/update diagram * Apply suggestions from code review Co-authored-by: Erin Shaben * update overview page --------- Co-authored-by: Erin Shaben Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> --- products/cctp-bridge/overview.md | 80 +++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/products/cctp-bridge/overview.md b/products/cctp-bridge/overview.md index 30404ce4c..13c4e48f8 100644 --- a/products/cctp-bridge/overview.md +++ b/products/cctp-bridge/overview.md @@ -1 +1,79 @@ -TODO \ No newline at end of file +--- +title: CCTP Bridge with Wormhole +description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. +categories: Transfer +--- + +# CCTP with Wormhole Overview + +The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. + +## Key Features + +- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. +- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. +- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. +- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. +- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. +- **Gas payment**: Covering destination gas in automated vs. manual transfers. + - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. + - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. + +## How It Works + +This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. + +1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. + +2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. + +3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. + +4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. + +5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. + +```mermaid +sequenceDiagram + participant User as Alice + participant SourceChain as Circle Bridge
on Ethereum + participant Circle + participant Guardians as Wormhole Guardians + participant Relayer + participant DestinationChain as Circle Bridge
on Avalanche + + User->>SourceChain: Submit transfer
(100 USDC to Avalanche) + SourceChain->>Circle: Initiate a burn + Circle->>Circle: Burn USDC and provide attestation + SourceChain->>Guardians: Emit Wormhole message (transfer metadata) + Guardians->>Guardians: Sign message and produce VAA + Relayer->>Guardians: Fetch signed VAA + Relayer->>Circle: Fetch Circle burn attestation + Relayer->>DestinationChain: Submit VAA and
attestation + DestinationChain->>Circle: Verify Circle attestation + Circle->>User: Mint USDC to Alice +``` + +!!! note + For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. + +## Use Cases + +Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: + +- **USDC Payments Across Chains** + - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. + - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. + +- **USDC-Powered Multichain Settlement** + - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. + +## Next Steps + +Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: + +- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. +- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. \ No newline at end of file From 8bd17b3223505d79afc603483267774e9273bf25 Mon Sep 17 00:00:00 2001 From: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Date: Thu, 29 May 2025 16:19:30 -0400 Subject: [PATCH 33/55] Updated Get Started with Messaging + Solidity SDK Get Started (#401) * adds `sign-evm.md` and starts content * adds content to evm signer for private key encryption * These deletions are part of a branch I've since deleted so I'm just removing them here * Creates "Create and Use Messaging Contracts" guide in Solidity SDK section, updates snippets & image * moves items to change contract demo to Solidity Get Started and add new messaging get started using core * update links and add TODOs * updates per review feedback * Apply suggestions from code review Co-authored-by: Erin Shaben * WIP * finish content, update snippets where needed, grammarly pass * remove old terminal outputs (no longer needed) * updates example to shorten, adds more tool specific info for users * review edits * apply review feedback * grammarly pass * Apply suggestions from code review Co-authored-by: Erin Shaben * applied feedback per review * review feedback * Apply suggestions from code review * update solidity sdk page * Apply suggestions from code review --------- Co-authored-by: Erin Shaben --- .../products/messaging/get-started/main.ts | 183 ++++++++++++++++++ .../get-started/terminal-output-01.html | 8 - .../get-started/terminal-output-02.html | 12 -- .../get-started/terminal-output-03.html | 6 - .../get-started/terminal-output-04.html | 7 - .../get-started/terminal-output-05.html | 9 - .../messaging/get-started/terminal01.html | 21 ++ .../get-started/solidity-sdk-1.sol | 62 ++++++ .../get-started/solidity-sdk-2.sol | 43 ++++ .../get-started/solidity-sdk-3.ts | 140 ++++++++++++++ .../get-started/terminal-output-01.html | 10 + .../sdk-reference/solidity-sdk-1.sol | 12 -- .../sdk-reference/solidity-sdk-2.sol | 55 ------ .../sdk-reference/solidity-sdk-3.sol | 26 --- .../sdk-reference/solidity-sdk-4.sol | 20 -- .../sdk-reference/solidity-sdk-5.sol | 22 --- products/messaging/get-started.md | 150 +++++--------- tools/solidity-sdk/get-started.md | 139 ++++++++++++- 18 files changed, 648 insertions(+), 277 deletions(-) create mode 100644 .snippets/code/products/messaging/get-started/main.ts delete mode 100644 .snippets/code/products/messaging/get-started/terminal-output-01.html delete mode 100644 .snippets/code/products/messaging/get-started/terminal-output-02.html delete mode 100644 .snippets/code/products/messaging/get-started/terminal-output-03.html delete mode 100644 .snippets/code/products/messaging/get-started/terminal-output-04.html delete mode 100644 .snippets/code/products/messaging/get-started/terminal-output-05.html create mode 100644 .snippets/code/products/messaging/get-started/terminal01.html create mode 100644 .snippets/code/tools/solidity-sdk/get-started/solidity-sdk-1.sol create mode 100644 .snippets/code/tools/solidity-sdk/get-started/solidity-sdk-2.sol create mode 100644 .snippets/code/tools/solidity-sdk/get-started/solidity-sdk-3.ts create mode 100644 .snippets/code/tools/solidity-sdk/get-started/terminal-output-01.html delete mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol delete mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol delete mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol delete mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol delete mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol diff --git a/.snippets/code/products/messaging/get-started/main.ts b/.snippets/code/products/messaging/get-started/main.ts new file mode 100644 index 000000000..d0fd1c804 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/main.ts @@ -0,0 +1,183 @@ +import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); \ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-01.html b/.snippets/code/products/messaging/get-started/terminal-output-01.html deleted file mode 100644 index cbdfc5da8..000000000 --- a/.snippets/code/products/messaging/get-started/terminal-output-01.html +++ /dev/null @@ -1,8 +0,0 @@ -
- forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s - Compiler run successful! - -
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-02.html b/.snippets/code/products/messaging/get-started/terminal-output-02.html deleted file mode 100644 index 35f37fa11..000000000 --- a/.snippets/code/products/messaging/get-started/terminal-output-02.html +++ /dev/null @@ -1,12 +0,0 @@ -
- forge test - [⠊] Compiling... - No files changed, compilation skipped - Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest - [PASS] testDeployment() (gas: 13544) - [PASS] testReceiveMessage() (gas: 22579) - [PASS] testSendMessage() (gas: 22719) - Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) - Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) - -
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-03.html b/.snippets/code/products/messaging/get-started/terminal-output-03.html deleted file mode 100644 index 8060464a6..000000000 --- a/.snippets/code/products/messaging/get-started/terminal-output-03.html +++ /dev/null @@ -1,6 +0,0 @@ -
- npm run deploy:sender - Enter keystore password: XXXXXXXXXXXX - MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 - -
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-04.html b/.snippets/code/products/messaging/get-started/terminal-output-04.html deleted file mode 100644 index cfccf1763..000000000 --- a/.snippets/code/products/messaging/get-started/terminal-output-04.html +++ /dev/null @@ -1,7 +0,0 @@ -
- npm run deploy:receiver - Enter keystore password: XXXXXXXXXXXX - MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 - Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) - -
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal-output-05.html b/.snippets/code/products/messaging/get-started/terminal-output-05.html deleted file mode 100644 index 1b2802c58..000000000 --- a/.snippets/code/products/messaging/get-started/terminal-output-05.html +++ /dev/null @@ -1,9 +0,0 @@ -
- npm run send:message - Enter keystore password: XXXXXXXXXXXX - Transaction sent, waiting for confirmation... - ... - Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 - You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET - -
\ No newline at end of file diff --git a/.snippets/code/products/messaging/get-started/terminal01.html b/.snippets/code/products/messaging/get-started/terminal01.html new file mode 100644 index 000000000..5df2deba0 --- /dev/null +++ b/.snippets/code/products/messaging/get-started/terminal01.html @@ -0,0 +1,21 @@ +
+ npx tsx main.ts + Wormhole SDK Initialized. + Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 + Source chain context obtained for: Sepolia + Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 + Message to send: "HelloWormholeSDK-1748362375390" + Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... + Signing and sending the message publication transaction(s)... + Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 + View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 + Waiting a few seconds for transaction to propagate before parsing... + Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... + --- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 + ----------------------------------------- + +
\ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-1.sol b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-1.sol new file mode 100644 index 000000000..c8f38ed10 --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-1.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} diff --git a/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-2.sol b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-2.sol new file mode 100644 index 000000000..9e5fb77bd --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-2.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} diff --git a/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-3.ts b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-3.ts new file mode 100644 index 000000000..5bffb4e34 --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/get-started/solidity-sdk-3.ts @@ -0,0 +1,140 @@ +import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); diff --git a/.snippets/code/tools/solidity-sdk/get-started/terminal-output-01.html b/.snippets/code/tools/solidity-sdk/get-started/terminal-output-01.html new file mode 100644 index 000000000..5e1a8e5d7 --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/get-started/terminal-output-01.html @@ -0,0 +1,10 @@ +
+ npx tsx script/transfer.ts + Initializing Wormhole SDK... + Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 + Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 + Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... + Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 + ✅ Transfer initiated successfully! + +
\ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol deleted file mode 100644 index 5e4b361f9..000000000 --- a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/constants/Chains.sol"; -import "wormhole-sdk/Utils.sol"; - -import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; -import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; -import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; -import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol deleted file mode 100644 index 7c54b6ba9..000000000 --- a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/Utils.sol"; - -abstract contract Base { - IWormholeRelayer public immutable wormholeRelayer; - IWormhole public immutable wormhole; - - address registrationOwner; - mapping(uint16 => bytes32) registeredSenders; - - constructor(address _wormholeRelayer, address _wormhole) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - wormhole = IWormhole(_wormhole); - registrationOwner = msg.sender; - } - - modifier onlyWormholeRelayer() { - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } - - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } - - /** - * Sets the registered address for 'sourceChain' to 'sourceAddress' - * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid - * - * Assumes only one sender per chain is valid - * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) - */ - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -} diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol deleted file mode 100644 index 7b6bcebac..000000000 --- a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; - -contract CrossChainSender is Base { - constructor( - address _wormholeRelayer, - address _wormhole - ) Base(_wormholeRelayer, _wormhole) {} - - function sendMessage( - bytes memory message, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Register sender and send message through WormholeRelayer - setRegisteredSender(targetChain, msg.sender); - onlyWormholeRelayer().sendPayloadToEvm( - targetChain, - address(targetAddress), - message, - 0, - 500_000 - ); - } -} diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol deleted file mode 100644 index c8344a06b..000000000 --- a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol +++ /dev/null @@ -1,20 +0,0 @@ -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenSender is TokenSender { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenSender(_wormholeRelayer, _wormhole) {} - - function sendToken( - address token, - uint256 amount, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Send tokens across chains - transferTokenToTarget(token, amount, targetChain, targetAddress); - } -} diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol deleted file mode 100644 index fd9c5a744..000000000 --- a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenReceiver is TokenReceiver { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenReceiver(_wormholeRelayer, _wormhole) {} - - // Function to handle received tokens from another chain - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable override { - // Process the received tokens here - receiveTokens(payload); - } -} diff --git a/products/messaging/get-started.md b/products/messaging/get-started.md index 165ab4c05..f7430d40f 100644 --- a/products/messaging/get-started.md +++ b/products/messaging/get-started.md @@ -1,149 +1,101 @@ --- title: Get Started with Messaging -description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. -categories: Messaging, Transfer +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK --- # Get Started with Messaging -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} - -## Introduction - -Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. ## Prerequisites -Before you begin, make sure you have the following: +Before you begin, ensure you have the following: -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key -- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} -- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} -- Wallet private key +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions -## Install and Set Up Project +## Configure Your Messaging Environment -1. Clone the demo repository and navigate to the project directory: +1. Create a directory and initialize a Node.js project: ```bash - git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git - cd demo-wormhole-messaging + mkdir core-message + cd core-message + npm init -y ``` -2. Use the following commands to install Foundry and project dependencies: +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: ```bash - npm install + npm install --save-dev tsx typescript @types/node ethers ``` -3. Use Foundry's Forge to compile the contracts in the repository: +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: ```bash - forge build + npx tsc --init ``` - You will see terminal output similar to the following, confirming the contracts were compiled successfully: - - --8<-- "code/products/messaging/get-started/terminal-output-01.html" - -4. Run tests to ensure everything is functioning correctly before deployment: - - ```bash - forge test - ``` - - You will see passing results for all test cases in the terminal output: - - --8<-- "code/products/messaging/get-started/terminal-output-02.html" - -## Prepare for Contract Deployment - -This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: - -- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji -- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores - -The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. - -### Encrypt Private Key - -Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. - -1. Create a Foundry keystore to encrypt your wallet private key using the following command: - - ```bash - cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } ``` -2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: ```bash - Enter password: INSERT_DECRYPTION_PASSWORD + npm install @wormhole-foundation/sdk ``` -3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required - -## Deploy Sender Contract - -Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: - -1. Run the deployment script command in your terminal: +5. Create a new file named `main.ts`: ```bash - npm run deploy:sender + touch main.ts ``` -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - - --8<-- "code/products/messaging/get-started/terminal-output-03.html" - - The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. - -## Deploy Receiver Contract - -Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: +## Construct and Publish Your Message -1. Run the deployment script command in your terminal: +1. Open `main.ts` and update the code there as follows: - ```bash - npm run deploy:receiver + ```ts title="main.ts" + --8<-- "code/products/messaging/get-started/main.ts" ``` -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - - --8<-- "code/products/messaging/get-started/terminal-output-04.html" - - - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file - - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. -## Send Your First Message - -Follow these steps to use your deployed contracts and send your first message: - -1. Run the `sendMessage.ts` script using the following command: +2. Run the script using the following command: ```bash - npm run send:message + npx tsx main.ts ``` -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - - --8<-- "code/products/messaging/get-started/terminal-output-05.html" + You will see terminal output similar to the following: -4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: + --8<-- "code/products/messaging/get-started/terminal01.html" - ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages -Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. ## Next Steps - +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. \ No newline at end of file diff --git a/tools/solidity-sdk/get-started.md b/tools/solidity-sdk/get-started.md index 30404ce4c..5f2bc2033 100644 --- a/tools/solidity-sdk/get-started.md +++ b/tools/solidity-sdk/get-started.md @@ -1 +1,138 @@ -TODO \ No newline at end of file +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + --8<-- "code/tools/solidity-sdk/get-started/solidity-sdk-1.sol" + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + --8<-- "code/tools/solidity-sdk/get-started/solidity-sdk-2.sol" + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + --8<-- "code/tools/solidity-sdk/get-started/solidity-sdk-3.ts" + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + + --8<-- "code/tools/solidity-sdk/get-started/terminal-output-01.html" + +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. From 3f9625bec28c568fb2f43f9174f4c00b20c70922 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 06:19:55 -0400 Subject: [PATCH 34/55] Solidity SDK temporary clean up (#434) * update solidity sdk reference * Update tools/solidity-sdk/sdk-reference.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../sdk-reference/solidity-sdk-1.sol | 12 ++++ .../sdk-reference/solidity-sdk-2.sol | 55 +++++++++++++++++++ .../sdk-reference/solidity-sdk-3.sol | 26 +++++++++ .../sdk-reference/solidity-sdk-4.sol | 20 +++++++ .../sdk-reference/solidity-sdk-5.sol | 22 ++++++++ tools/solidity-sdk/sdk-reference.md | 32 ++++------- 6 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol create mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol create mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol create mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol create mode 100644 .snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol new file mode 100644 index 000000000..2293c104c --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/constants/Chains.sol"; +import "wormhole-sdk/Utils.sol"; + +import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; +import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; +import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; +import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; \ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol new file mode 100644 index 000000000..03beddc4e --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/interfaces/IWormhole.sol"; +import "wormhole-sdk/Utils.sol"; + +abstract contract Base { + IWormholeRelayer public immutable wormholeRelayer; + IWormhole public immutable wormhole; + + address registrationOwner; + mapping(uint16 => bytes32) registeredSenders; + + constructor(address _wormholeRelayer, address _wormhole) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + wormhole = IWormhole(_wormhole); + registrationOwner = msg.sender; + } + + modifier onlyWormholeRelayer() { + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } + + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } + + /** + * Sets the registered address for 'sourceChain' to 'sourceAddress' + * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid + * + * Assumes only one sender per chain is valid + * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) + */ + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } +} \ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol new file mode 100644 index 000000000..ff3994ebf --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; + +contract CrossChainSender is Base { + constructor( + address _wormholeRelayer, + address _wormhole + ) Base(_wormholeRelayer, _wormhole) {} + + function sendMessage( + bytes memory message, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Register sender and send message through WormholeRelayer + setRegisteredSender(targetChain, msg.sender); + onlyWormholeRelayer().sendPayloadToEvm( + targetChain, + address(targetAddress), + message, + 0, + 500_000 + ); + } +} \ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol new file mode 100644 index 000000000..dcf9c43c5 --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenSender is TokenSender { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenSender(_wormholeRelayer, _wormhole) {} + + function sendToken( + address token, + uint256 amount, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Send tokens across chains + transferTokenToTarget(token, amount, targetChain, targetAddress); + } +} \ No newline at end of file diff --git a/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol new file mode 100644 index 000000000..a0bc97d14 --- /dev/null +++ b/.snippets/code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenReceiver is TokenReceiver { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenReceiver(_wormholeRelayer, _wormhole) {} + + // Function to handle received tokens from another chain + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable override { + // Process the received tokens here + receiveTokens(payload); + } +} \ No newline at end of file diff --git a/tools/solidity-sdk/sdk-reference.md b/tools/solidity-sdk/sdk-reference.md index 880e61e16..06523bcbc 100644 --- a/tools/solidity-sdk/sdk-reference.md +++ b/tools/solidity-sdk/sdk-reference.md @@ -6,42 +6,32 @@ categories: Solidity-SDK # Solidity SDK -## Introduction +This page covers all you need to know about the functionality offered through the Wormhole Solidity SDK. -The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains. +
-By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides: +- :octicons-download-16:{ .lg .middle } **Installation** - - **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure - - **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain - - **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement - - **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments + --- -These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains. + Find installation instructions using Foundry and Forge to pull the necessary libraries into your project. -This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing. + [:custom-arrow: Install the SDK](/docs/tools/solidity-sdk/get-started/#installation) -## Installation +- :octicons-download-16:{ .lg .middle } **Source Code** -To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project: + --- -```bash -forge install wormhole-foundation/wormhole-solidity-sdk@v0.1.0 -``` - -When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file: + Want to go straight to the source? Check out the Solidity SDK GitHub repository. -```toml -evm_version = "paris" -``` + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} -This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades. +
## Key Considerations Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind: - - **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes - **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries - **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments From 9007110a614323af1b62e6c61baa45ca72f797eb Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 06:31:20 -0400 Subject: [PATCH 35/55] Pull in latest changes from main to the staging branch (#436) * update sdk to the latest version (#374) * Add gitignore step (#372) * add instructions for including .gitignore when starting fresh projects * update llms --------- Co-authored-by: Martin Hofmann * update sdk to latest version (#386) * multiple ntt cli feedback adjustments (#389) * multiple ntt cli feedback adjustments * generate llms * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * re-generate llms files --------- Co-authored-by: Erin Shaben * Martinh/faq link in ntt (#384) * add faws link to solana deployment page * llms check * update notes * llm check * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * update based on feedback * llm check * action orientated link * llm check --------- Co-authored-by: Erin Shaben * Martinh/settlement grammar fix (#391) * fix(docs): fix grammar in unified liquidity paragraph (#390) * grammarly check * llm check --------- Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> * remove Connect from product comparison table (#396) * remove Connect from product comparison table * llms check --------- Co-authored-by: Ilaria Enache * Staked rpc comment & feature matrix adjustment (#402) * staked rpc comment for ntt solana deploy * adjust comment * adjust feature support matrix for sui & aptos cctp * re-generate llms files * Martinh/tutorial supported chains (#400) * update supported chains in tutorial * llm check --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * update sdk to latest version (#399) * Martinh/update supported networks (#383) * add tables * add multigov compatible chains * ntt supported chains * update connect supported chains * llm check * automated table creation for supported blockchains by product * llm check * update table titles * llm check * update supported networks * llm check * update title * llm check * Update build/start-building/supported-networks.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update metadata description and title * llm check * llm check * supported chains per product in single snippets * llm check * update supported chains for token bridge and cctp * llm check * remove extre symbol at the end of tables * llm check --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * fix spacing (#416) * fix spacing * llms generation * Message fee (#415) * add messageFee value to relevant functions * remove comment * llms check --------- Co-authored-by: Ilaria Enache * Martinh/update sdk v1.19.0 (#406) * update sdk to latest version * add new chain via npm run generate * update ntt and multigov supported chains tables * llm check * support for seievm mainnet in sdk v1.20.0 (#417) * support for seievm mainnet * bump sdk variable to v1.20.0 * generate llms --------- Co-authored-by: Erin Shaben * rollback example changes (#418) * rollback example changes * update llms --------- Co-authored-by: Martin Hofmann Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: evgeniko <97796468+evgeniko@users.noreply.github.com> Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Ilaria Enache --- .../transfers/cctp/CircleIntegration.sol | 2 +- .../guides/core-contracts/attestToken.sol | 8 + .../guides/core-contracts/transferTokens.sol | 14 + .../transferTokensWithPayload.sol | 14 + .../start-building/supported-networks/cctp.md | 10 + .../supported-networks/connect.md | 10 + .../supported-networks/multigov.md | 10 + .../start-building/supported-networks/ntt.md | 10 + .../supported-networks/settlement.md | 10 + .../supported-networks/token-bridge.md | 10 + .../products/reference/chain-ids/chain-ids.md | 4 +- .../consistency-levels/consistency-levels.md | 2 +- .../contract-addresses/core-contracts.md | 2 +- .../contract-addresses/token-bridge.md | 2 +- .snippets/text/supported-networks.md | 158 - llms-files/llms-basics.txt | 784 ++- llms-files/llms-connect.txt | 1102 ++++- llms-files/llms-multigov.txt | 1049 +++- llms-files/llms-ntt.txt | 1137 ++++- llms-files/llms-queries.txt | 1156 ++++- llms-files/llms-reference.txt | 253 +- llms-files/llms-relayers.txt | 1035 +++- llms-files/llms-settlement.txt | 1151 ++++- llms-files/llms-solidity-sdk.txt | 1586 ++++-- llms-files/llms-token-bridge.txt | 1453 +++++- llms-files/llms-transfer.txt | 1958 ++++++-- llms-files/llms-typescript-sdk.txt | 1585 +++++- llms-full.txt | 4317 +++++++++-------- llms.txt | 26 +- .../guides/deploy-to-solana.md | 15 +- products/reference/supported-networks.md | 23 +- .../tutorials/transfer-workflow.md | 2 +- variables.yml | 2 +- 33 files changed, 14634 insertions(+), 4266 deletions(-) create mode 100644 .snippets/code/products/messaging/guides/core-contracts/attestToken.sol create mode 100644 .snippets/code/products/messaging/guides/core-contracts/transferTokens.sol create mode 100644 .snippets/code/products/messaging/guides/core-contracts/transferTokensWithPayload.sol create mode 100644 .snippets/text/build/start-building/supported-networks/cctp.md create mode 100644 .snippets/text/build/start-building/supported-networks/connect.md create mode 100644 .snippets/text/build/start-building/supported-networks/multigov.md create mode 100644 .snippets/text/build/start-building/supported-networks/ntt.md create mode 100644 .snippets/text/build/start-building/supported-networks/settlement.md create mode 100644 .snippets/text/build/start-building/supported-networks/token-bridge.md delete mode 100644 .snippets/text/supported-networks.md diff --git a/.snippets/code/build/transfers/cctp/CircleIntegration.sol b/.snippets/code/build/transfers/cctp/CircleIntegration.sol index 68b54b367..2a2bbe973 100644 --- a/.snippets/code/build/transfers/cctp/CircleIntegration.sol +++ b/.snippets/code/build/transfers/cctp/CircleIntegration.sol @@ -69,7 +69,7 @@ contract CircleIntegration is // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` // should be the target contract (or wallet) composing on this contract. - (uint64 nonce, uint256 amountReceived) = _transferTokens( + (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}( transferParams.token, transferParams.amount, transferParams.targetChain, diff --git a/.snippets/code/products/messaging/guides/core-contracts/attestToken.sol b/.snippets/code/products/messaging/guides/core-contracts/attestToken.sol new file mode 100644 index 000000000..bebc0382c --- /dev/null +++ b/.snippets/code/products/messaging/guides/core-contracts/attestToken.sol @@ -0,0 +1,8 @@ +IWormhole wormhole = IWormhole(wormholeAddr); + +uint256 wormholeFee = wormhole.messageFee(); + +wormhole.attestToken{value: wormholeFee}( + address(tokenImpl), // the token contract to attest + 234 // nonce for the transfer +); \ No newline at end of file diff --git a/.snippets/code/products/messaging/guides/core-contracts/transferTokens.sol b/.snippets/code/products/messaging/guides/core-contracts/transferTokens.sol new file mode 100644 index 000000000..5b38f9480 --- /dev/null +++ b/.snippets/code/products/messaging/guides/core-contracts/transferTokens.sol @@ -0,0 +1,14 @@ +IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokens{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + arbiterFee, // fee for relayer + nonce // nonce for this transfer +); \ No newline at end of file diff --git a/.snippets/code/products/messaging/guides/core-contracts/transferTokensWithPayload.sol b/.snippets/code/products/messaging/guides/core-contracts/transferTokensWithPayload.sol new file mode 100644 index 000000000..44e16cb39 --- /dev/null +++ b/.snippets/code/products/messaging/guides/core-contracts/transferTokensWithPayload.sol @@ -0,0 +1,14 @@ +IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokensWithPayload{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + nonce, // nonce for this transfer + additionalPayload // additional payload data +); \ No newline at end of file diff --git a/.snippets/text/build/start-building/supported-networks/cctp.md b/.snippets/text/build/start-building/supported-networks/cctp.md new file mode 100644 index 000000000..a8cffa344 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/cctp.md @@ -0,0 +1,10 @@ + + +
+ +### CCTP + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/build/start-building/supported-networks/connect.md b/.snippets/text/build/start-building/supported-networks/connect.md new file mode 100644 index 000000000..10c8ff09f --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/connect.md @@ -0,0 +1,10 @@ + + +
+ +### Connect + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SolanaSVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AptosMove VM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BerachainEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BNB Smart ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MezoEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OsmosisCosmWasm:x::x::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SuiSui Move VM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
TerraCosmWasm:x::x::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/build/start-building/supported-networks/multigov.md b/.snippets/text/build/start-building/supported-networks/multigov.md new file mode 100644 index 000000000..222a7538d --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/multigov.md @@ -0,0 +1,10 @@ + + +
+ +### MultiGov + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AcalaEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BerachainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BlastEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
CeloEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
FantomEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
GnosisEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
HyperEVMEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
InkEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaiaEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaruraEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
LineaEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MantleEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MezoEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MonadEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MoonbeamEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
NeonEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OasisEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ScrollEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SeiCosmWasm:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SeievmEVM:white_check_mark::white_check_mark::white_check_mark:
SNAXchainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SonicEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
World ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
X LayerEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/build/start-building/supported-networks/ntt.md b/.snippets/text/build/start-building/supported-networks/ntt.md new file mode 100644 index 000000000..1bb1715e9 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/ntt.md @@ -0,0 +1,10 @@ + + +
+ +### NTT + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AcalaEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BerachainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
GnosisEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
HyperEVMEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
InkEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaiaEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaruraEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
LineaEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MezoEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MonadEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
NeonEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OasisEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SeievmEVM:white_check_mark::white_check_mark::x:
SNAXchainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/build/start-building/supported-networks/settlement.md b/.snippets/text/build/start-building/supported-networks/settlement.md new file mode 100644 index 000000000..532bd9d38 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/settlement.md @@ -0,0 +1,10 @@ + + +
+ +### Settlement + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SolanaSVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SuiSui Move VM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::x::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/build/start-building/supported-networks/token-bridge.md b/.snippets/text/build/start-building/supported-networks/token-bridge.md new file mode 100644 index 000000000..67588c42d --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/token-bridge.md @@ -0,0 +1,10 @@ + + +
+ +### Token Bridge + +
BlockchainEnvironmentMainnetTestnetDevnetQuick Links
EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AcalaEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AlgorandAVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AptosMove VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BerachainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
HyperEVMEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
InjectiveCosmWasm:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
InkEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaiaEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
KaruraEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
LineaEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MezoEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MonadEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
NEARNEAR VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
NeonEVM:x::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OasisEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SeiCosmWasm:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SeievmEVM:white_check_mark::white_check_mark::x:
SNAXchainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
SuiSui Move VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
TerraCosmWasm:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
Terra 2.0CosmWasm:white_check_mark::white_check_mark::white_check_mark::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
XPLACosmWasm:white_check_mark::white_check_mark::x::material-web: Website
:material-file-document: Developer Docs
:octicons-package-16: Block Explorer
+ +
+ diff --git a/.snippets/text/products/reference/chain-ids/chain-ids.md b/.snippets/text/products/reference/chain-ids/chain-ids.md index 4af0422ac..4d438ef80 100644 --- a/.snippets/text/products/reference/chain-ids/chain-ids.md +++ b/.snippets/text/products/reference/chain-ids/chain-ids.md @@ -3,10 +3,10 @@ === "Mainnet" -
Chain NameWormhole Chain IDNetwork ID
Ethereum21
Solana1Mainnet Beta - 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
Acala12787
Algorand8mainnet-v1.0
Aptos221
Arbitrum23Arbitrum One - 42161
Avalanche6C-Chain - 43114
Base30Base - 8453
Berachain39
Blast3681457
BNB Smart Chain456
Celestia4004celestia
Celo1442220
Cosmos Hub4000cosmoshub-4
Dymension4007dymension_1100-1
Evmos4001evmos_9001-2
Fantom10250
Gnosis25100
HyperEVM47
Injective19injective-1
Ink46
Kaia138217
Karura11686
Kujira4002kaiyo-1
Linea3859144
Mantle355000
Mezo50
Monad48
Moonbeam161284
NEAR15mainnet
Neon17245022934
Neutron4003neutron-1
Noble4009noble-1
Oasis742262
Optimism2410
Osmosis20osmosis-1
Polygon5137
Provenance4008pio-mainnet-1
Pythnet26
Scroll34534352
SEDA4006
Sei32pacific-1
Seievm40
SNAXchain432192
Stargaze4005stargaze-1
Sui2135834a8a
Terra3columbus-5
Terra 2.018phoenix-1
Unichain44
World Chain45480
X Layer37196
XPLA28dimension_37-1
+
Chain NameWormhole Chain IDNetwork ID
Ethereum21
Solana1Mainnet Beta - 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
Acala12787
Algorand8mainnet-v1.0
Aptos221
Arbitrum23Arbitrum One - 42161
Avalanche6C-Chain - 43114
Base30Base - 8453
Berachain39
Blast3681457
BNB Smart Chain456
Celestia4004celestia
Celo1442220
Cosmos Hub4000cosmoshub-4
Dymension4007dymension_1100-1
Evmos4001evmos_9001-2
Fantom10250
Gnosis25100
HyperEVM47
Injective19injective-1
Ink46
Kaia138217
Karura11686
Kujira4002kaiyo-1
Linea3859144
Mantle355000
Mezo50
Monad48
Moonbeam161284
NEAR15mainnet
Neon17245022934
Neutron4003neutron-1
Noble4009noble-1
Oasis742262
Optimism2410
Osmosis20osmosis-1
Polygon5137
Provenance4008pio-mainnet-1
Pythnet26
Scroll34534352
SEDA4006
Sei32pacific-1
Seievm40
SNAXchain432192
Sonic52146
Stargaze4005stargaze-1
Sui2135834a8a
Terra3columbus-5
Terra 2.018phoenix-1
Unichain44
World Chain45480
X Layer37196
XPLA28dimension_37-1
=== "Testnet" -
Chain NameWormhole Chain IDNetwork ID
Ethereum Holesky10006Holesky - 17000
Ethereum Sepolia10002Sepolia - 11155111
Solana1Devnet - EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
Acala12597
Algorand8testnet-v1.0
Aptos222
Arbitrum Sepolia10003Sepolia - 421614
Avalanche6Fuji - 43113
Base Sepolia10004Base Sepolia - 84532
Berachain3980084
Blast36168587773
BNB Smart Chain497
Celestia4004mocha-4
Celo14Alfajores - 44787
Cosmos Hub4000theta-testnet-001
Dymension4007
Evmos4001evmos_9000-4
Fantom104002
Gnosis25Chiado - 10200
HyperEVM47998
Injective19injective-888
Ink46763373
Kaia13Kairos - 1001
Karura11596
Kujira4002harpoon-4
Linea3859141
Mantle35Sepolia - 5003
Mezo5031611
Monad4810143
Moonbeam16Moonbase-Alphanet - 1287
NEAR15testnet
Neon17245022940
Neutron4003pion-1
Noble4009grand-1
Oasis742261
Optimism Sepolia10005Optimism Sepolia - 11155420
Osmosis20osmo-test-5
Polygon Amoy10007Amoy - 80002
Provenance4008
Pythnet26
Scroll34Sepolia - 534351
SEDA4006seda-1-testnet
Sei32atlantic-2
Seievm40
SNAXchain4313001
Stargaze4005
Sui214c78adac
Terra3bombay-12
Terra 2.018pisco-1
Unichain44Unichain Sepolia - 1301
World Chain454801
X Layer37195
XPLA28cube_47-5
+
Chain NameWormhole Chain IDNetwork ID
Ethereum Holesky10006Holesky - 17000
Ethereum Sepolia10002Sepolia - 11155111
Solana1Devnet - EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
Acala12597
Algorand8testnet-v1.0
Aptos222
Arbitrum Sepolia10003Sepolia - 421614
Avalanche6Fuji - 43113
Base Sepolia10004Base Sepolia - 84532
Berachain3980084
Blast36168587773
BNB Smart Chain497
Celestia4004mocha-4
Celo14Alfajores - 44787
Cosmos Hub4000theta-testnet-001
Dymension4007
Evmos4001evmos_9000-4
Fantom104002
Gnosis25Chiado - 10200
HyperEVM47998
Injective19injective-888
Ink46763373
Kaia13Kairos - 1001
Karura11596
Kujira4002harpoon-4
Linea3859141
Mantle35Sepolia - 5003
Mezo5031611
Monad4810143
Moonbeam16Moonbase-Alphanet - 1287
NEAR15testnet
Neon17245022940
Neutron4003pion-1
Noble4009grand-1
Oasis742261
Optimism Sepolia10005Optimism Sepolia - 11155420
Osmosis20osmo-test-5
Polygon Amoy10007Amoy - 80002
Provenance4008
Pythnet26
Scroll34Sepolia - 534351
SEDA4006seda-1-testnet
Sei32atlantic-2
Seievm40
SNAXchain4313001
Sonic5257054
Stargaze4005
Sui214c78adac
Terra3bombay-12
Terra 2.018pisco-1
Unichain44Unichain Sepolia - 1301
World Chain454801
X Layer37195
XPLA28cube_47-5
\ No newline at end of file diff --git a/.snippets/text/products/reference/consistency-levels/consistency-levels.md b/.snippets/text/products/reference/consistency-levels/consistency-levels.md index 18bd1c342..cc7221a5b 100644 --- a/.snippets/text/products/reference/consistency-levels/consistency-levels.md +++ b/.snippets/text/products/reference/consistency-levels/consistency-levels.md @@ -1,4 +1,4 @@ -
ChainInstantSafeFinalizedOtherwiseTime to FinalizeDetails
Ethereum200201finalized~ 19minDetails
Solana01~ 14sDetails
Acala200201finalized~ 24s
Algorand0~ 4sDetails
Aptos0~ 4sDetails
Arbitrum200201finalized~ 18minDetails
Avalanche200finalized~ 2sDetails
Base200201finalized~ 18min
Berachain200finalized~ 4s
Blast200201finalized~ 18min
BNB Smart Chain200201finalized~ 48sDetails
Celestia0~ 5s
Celo200finalized~ 10s
Cosmos Hub0~ 5s
Dymension0~ 5s
Evmos0~ 2s
Fantom200finalized~ 5s
Injective0~ 3s
Ink0~ 9min
Kaia200finalized~ 1s
Karura200201finalized~ 24sDetails
Kujira0~ 3s
Mantle200201finalized~ 18min
Mezo0~ 8s
Monad0~ 2s
Moonbeam200201finalized~ 24sDetails
NEAR0~ 2sDetails
Neutron0~ 5s
Oasis200finalized~ 12s
Optimism200201finalized~ 18min
Osmosis0~ 6s
Polygon200finalized~ 66sDetails
Scroll200finalized~ 16min
Sei0~ 1s
Stargaze0~ 5s
Sui0~ 3sDetails
Terra0~ 6s
Terra 2.00~ 6s
Unichain200201finalized~ 18min
World Chain0~ 18min
X Layer200201finalized~ 16min
XPLA0~ 5s
+
ChainInstantSafeFinalizedOtherwiseTime to FinalizeDetails
Ethereum200201finalized~ 19minDetails
Solana01~ 14sDetails
Acala200201finalized~ 24s
Algorand0~ 4sDetails
Aptos0~ 4sDetails
Arbitrum200201finalized~ 18minDetails
Avalanche200finalized~ 2sDetails
Base200201finalized~ 18min
Berachain200finalized~ 4s
Blast200201finalized~ 18min
BNB Smart Chain200201finalized~ 48sDetails
Celestia0~ 5s
Celo200finalized~ 10s
Cosmos Hub0~ 5s
Dymension0~ 5s
Evmos0~ 2s
Fantom200finalized~ 5s
Injective0~ 3s
Ink0~ 9min
Kaia200finalized~ 1s
Karura200201finalized~ 24sDetails
Kujira0~ 3s
Mantle200201finalized~ 18min
Mezo0~ 8s
Monad0~ 2s
Moonbeam200201finalized~ 24sDetails
NEAR0~ 2sDetails
Neutron0~ 5s
Oasis200finalized~ 12s
Optimism200201finalized~ 18min
Osmosis0~ 6s
Polygon200finalized~ 66sDetails
Scroll200finalized~ 16min
Sei0~ 1s
Sonic0~ 1s
Stargaze0~ 5s
Sui0~ 3sDetails
Terra0~ 6s
Terra 2.00~ 6s
Unichain200201finalized~ 18min
World Chain0~ 18min
X Layer200201finalized~ 16min
XPLA0~ 5s
diff --git a/.snippets/text/products/reference/contract-addresses/core-contracts.md b/.snippets/text/products/reference/contract-addresses/core-contracts.md index 1a0ad07c8..1a294ccf7 100644 --- a/.snippets/text/products/reference/contract-addresses/core-contracts.md +++ b/.snippets/text/products/reference/contract-addresses/core-contracts.md @@ -3,7 +3,7 @@ === "Mainnet" -
Chain NameContract Address
Ethereum0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
Solanaworm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
Acala0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Algorand842125965
Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
Arbitrum0xa5f208e072434bC67592E4C49C1B991BA79BCA46
Avalanche0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c
Base0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Berachain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
Blast0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
BNB Smart Chain0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
Celo0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Fantom0x126783A6Cb203a3E35344528B26ca3a0489a1485
Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Injectiveinj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d
Ink0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
Kaia0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7
Karura0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Mantle0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Moonbeam0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3
NEARcontract.wormhole_crypto.near
Neutronneutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh
Oasis0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585
Optimism0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722
Polygon0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7
PythnetH3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU
Scroll0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Seisei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn
SNAXchain0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4
Sui0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c
Terraterra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5
Terra 2.0terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp
Unichain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
World Chain0xcbcEe4e081464A15d8Ad5f58BB493954421eB506
X Layer0x194B123c5E96B9b2E49763619985790Dc241CAC0
XPLAxpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w
+
Chain NameContract Address
Ethereum0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
Solanaworm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
Acala0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Algorand842125965
Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
Arbitrum0xa5f208e072434bC67592E4C49C1B991BA79BCA46
Avalanche0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c
Base0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Berachain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
Blast0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
BNB Smart Chain0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
Celo0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Fantom0x126783A6Cb203a3E35344528B26ca3a0489a1485
Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Injectiveinj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d
Ink0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
Kaia0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7
Karura0xa321448d90d4e5b0A732867c18eA198e75CAC48E
Mantle0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Moonbeam0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3
NEARcontract.wormhole_crypto.near
Neutronneutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh
Oasis0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585
Optimism0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722
Polygon0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7
PythnetH3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU
Scroll0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
Seisei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn
Seievm0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
SNAXchain0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4
Sui0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c
Terraterra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5
Terra 2.0terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp
Unichain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
World Chain0xcbcEe4e081464A15d8Ad5f58BB493954421eB506
X Layer0x194B123c5E96B9b2E49763619985790Dc241CAC0
XPLAxpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w
=== "Testnet" diff --git a/.snippets/text/products/reference/contract-addresses/token-bridge.md b/.snippets/text/products/reference/contract-addresses/token-bridge.md index 09ed8ea32..f88b2a607 100644 --- a/.snippets/text/products/reference/contract-addresses/token-bridge.md +++ b/.snippets/text/products/reference/contract-addresses/token-bridge.md @@ -3,7 +3,7 @@ === "Mainnet" -
Chain NameContract Address
Ethereum0x3ee18B2214AFF97000D974cf647E7C347E8fa585
SolanawormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
Acala0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
Algorand842126029
Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
Arbitrum0x0b2402144Bb366A632D14B83F244D2e0e21bD39c
Avalanche0x0e082F06FF657D94310cB8cE8B0D9a04541d8052
Base0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627
Berachain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
Blast0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
BNB Smart Chain0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7
Celo0x796Dff6D74F3E27060B71255Fe517BFb23C93eed
Fantom0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2
Injectiveinj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn
Ink0x3Ff72741fd67D6AD0668d93B41a09248F4700560
Kaia0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F
Karura0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
Mantle0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
Moonbeam0xb1731c586ca89a23809861c6103f0b96b3f57d92
NEARcontract.portalbridge.near
Oasis0x5848C791e09901b40A9Ef749f2a6735b418d7564
Optimism0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b
Polygon0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE
Scroll0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
Seisei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3
SNAXchain0x8B94bfE456B48a6025b92E11Be393BAa86e68410
Sui0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9
Terraterra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf
Terra 2.0terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9
Unichain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
World Chain0xc309275443519adca74c9136b02A38eF96E3a1f6
X Layer0x5537857664B0f9eFe38C9f320F75fEf23234D904
XPLAxpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv
+
Chain NameContract Address
Ethereum0x3ee18B2214AFF97000D974cf647E7C347E8fa585
SolanawormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
Acala0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
Algorand842126029
Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
Arbitrum0x0b2402144Bb366A632D14B83F244D2e0e21bD39c
Avalanche0x0e082F06FF657D94310cB8cE8B0D9a04541d8052
Base0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627
Berachain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
Blast0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
BNB Smart Chain0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7
Celo0x796Dff6D74F3E27060B71255Fe517BFb23C93eed
Fantom0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2
Injectiveinj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn
Ink0x3Ff72741fd67D6AD0668d93B41a09248F4700560
Kaia0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F
Karura0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
Mantle0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
Moonbeam0xb1731c586ca89a23809861c6103f0b96b3f57d92
NEARcontract.portalbridge.near
Oasis0x5848C791e09901b40A9Ef749f2a6735b418d7564
Optimism0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b
Polygon0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE
Scroll0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
Seisei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3
Seievm0x3Ff72741fd67D6AD0668d93B41a09248F4700560
SNAXchain0x8B94bfE456B48a6025b92E11Be393BAa86e68410
Sui0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9
Terraterra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf
Terra 2.0terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9
Unichain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
World Chain0xc309275443519adca74c9136b02A38eF96E3a1f6
X Layer0x5537857664B0f9eFe38C9f320F75fEf23234D904
XPLAxpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv
=== "Testnet" diff --git a/.snippets/text/supported-networks.md b/.snippets/text/supported-networks.md deleted file mode 100644 index 77d33a1b1..000000000 --- a/.snippets/text/supported-networks.md +++ /dev/null @@ -1,158 +0,0 @@ - - -
- -### EVM - -
BlockchainEnvironmentMainnetTestnetQuick Links
EthereumEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
AcalaEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
ArbitrumEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
AvalancheEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
BaseEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
BerachainEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
BlastEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
BNB Smart ChainEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
CeloEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
FantomEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
GnosisEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
HyperEVMEVM:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
InkEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
KaiaEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
KaruraEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
LineaEVM:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
MantleEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
MezoEVM:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
MonadEVM:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
MoonbeamEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
NeonEVM:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
OasisEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
OptimismEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
PolygonEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
ScrollEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
SeievmEVM:x::white_check_mark:
SNAXchainEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
UnichainEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
World ChainEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
X LayerEVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### SVM - -
BlockchainEnvironmentMainnetTestnetQuick Links
SolanaSVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
PythnetSVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### AVM - -
BlockchainEnvironmentMainnetTestnetQuick Links
AlgorandAVM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### CosmWasm - -
BlockchainEnvironmentMainnetTestnetQuick Links
InjectiveCosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
NeutronCosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
OsmosisCosmWasm:x::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
SeiCosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
TerraCosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
Terra 2.0CosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
XPLACosmWasm:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### Move VM - -
BlockchainEnvironmentMainnetTestnetQuick Links
AptosMove VM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### NEAR VM - -
BlockchainEnvironmentMainnetTestnetQuick Links
NEARNEAR VM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -### Sui Move VM - -
BlockchainEnvironmentMainnetTestnetQuick Links
SuiSui Move VM:white_check_mark::white_check_mark: - :material-web: Website
- :material-file-document: Developer Docs
- :octicons-package-16: Block Explorer
- -
- diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index cebac9178..4ed11c0b3 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -8,6 +8,7 @@ This file includes documentation related to the category: Basics ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md [type: other] @@ -20,6 +21,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md [type: other] ## Full content for each doc page @@ -383,6 +385,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -1002,28 +1311,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -1918,75 +2227,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -2098,4 +2339,397 @@ For more information about submitting to the bug bounty programs, refer to the [ ## Learn More The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. --- END CONTENT --- \ No newline at end of file diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index a00b2c117..a88d6899f 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -22,6 +22,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] ## Full content for each doc page @@ -1716,6 +1717,72 @@ wormholeConnectHosted(container, { In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/overview/ +--- BEGIN CONTENT --- +--- +title: Wormhole Connect +description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. +categories: Connect, Transfer +--- + +# Connect Overview + +With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. + +## Key Features + +Wormhole connect's notable features include: + +- **In-app multichain transfers**: Bridge assets without leaving your app. +- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. +- **Customizable UI**: Style the bridge interface to match your brand. +- **Optional destination gas**: Provide gas for initial transactions on the target chain. +- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. + +Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. + +## How It Works + +When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: + +1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. +2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). +3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. +6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. +7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. + +!!! tip + If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. + +## Use Cases + +Here are some key use cases that highlight the power and versatility of Connect: + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains + - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + +- **Cross-Chain Payment Widgets** + + - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + +- **Web3 Game Asset Transfers** + + - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + +## Next Steps + +Add Connect to your app with these key setup steps: + +[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- @@ -2177,6 +2244,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -2796,28 +3170,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -3712,75 +4086,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -3894,6 +4200,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -3971,6 +4670,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -4027,6 +4727,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -4086,6 +4787,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -4142,6 +4844,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -4243,6 +4946,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -4430,95 +5134,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 4152c8c8f..3dd7766f8 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -390,7 +390,7 @@ Wormhole’s multichain messaging infrastructure connects the hub and spokes, en The diagram below illustrates this high-level architecture. -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/architecture-1.webp) ## Key Components @@ -510,7 +510,7 @@ MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensu This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. -![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ @@ -1143,19 +1143,19 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets - **Coordinated Protocol Upgrades Across Chains** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains - **Progressive Decentralization for Multichain DAOs** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub ## Next Steps @@ -1538,6 +1538,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -2157,28 +2464,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -3073,75 +3380,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -3255,6 +3494,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -3332,6 +3964,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -3388,6 +4021,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -3447,6 +4081,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -3503,6 +4138,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -3604,6 +4240,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3791,95 +4428,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 106f78db6..202a19b23 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -28,6 +28,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] @@ -1461,8 +1462,13 @@ categories: NTT, Transfer This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. + +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. + ## Prerequisites Before deploying NTT on Solana, ensure you have the following: @@ -1588,14 +1594,13 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. - ### Generate an NTT Program Key Pair Create a unique key pair for the NTT program: - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +```bash +solana-keygen grind --starts-with ntt:1 --ignore-case +``` ### Set Mint Authority @@ -1714,6 +1719,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -1906,6 +1919,89 @@ Enter a new value to adjust limits and click **Update**. The changes will take e ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer +--- + +## Native Token Transfers Overview + +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. + +## Key Features + +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps + + +## Deployment Models + +NTT offers two operational modes for your existing tokens: + +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token + +## Supported Token Standards + +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. + +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. + +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. + +## Deployment Process + +Here's a breakdown of the key steps involved when deploying NTT: + +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed + +## Use Cases + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + +- **Borrowing and Lending Across Chains** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + +- **Gas Abstraction** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + +- **Cross-Chain Payment Widgets** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + +- **Cross-Chain Staking** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + +## Next Steps + +Follow these steps to get started with NTT: + +[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- @@ -2465,6 +2561,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -3084,28 +3487,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -4000,75 +4403,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -4182,6 +4517,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -4259,6 +4987,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -4315,6 +5044,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -4374,6 +5104,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -4430,6 +5161,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -4531,6 +5263,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -4718,95 +5451,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### Token Bridge -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 0eafb578f..a8d7a1762 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -18,6 +18,8 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md [type: other] ## Full content for each doc page @@ -797,29 +799,29 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution - - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution + - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades - **Multichain Prediction Markets** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds - - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks ## Next Steps @@ -828,6 +830,105 @@ Follow these steps to get started with Queries: [timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ +--- BEGIN CONTENT --- +--- +title: Queries Supported Methods +description: Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. +categories: Queries +--- + +# Supported Methods + +Wormhole Queries provides on-demand access to [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}-attested on-chain data through a simple REST endpoint. It offers a faster, gasless alternative to traditional transaction-based data retrieval, removing the need for gas fees and transaction finality delays. Requests are handled off-chain and processed by the Guardians, delivering verified data efficiently and cost-effectively. + +This page describes Wormhole Queries, their functionality, and available methods, aiming to assist new developers in utilizing the service. + +## Supported Query Types + +Wormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains. + +!!! note + For a more comprehensive technical description and further specifics on each query type, please consult the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md). + + +### eth_call + +The [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} query type allows you to perform read-only calls to a smart contract on a specific block, identified by its number or hash. Some of eth_call's configurations include: + +- **Batching** - group multiple calls, even to different contracts, into a single query targeting the same block, which is processed as one batch RPC call to simplify on-chain verification +- **Capacity** - batch up to 255 individual in a single eth_call query +- **Result data** - provides the specified block's number, hash, timestamp, and the output from the contract call + +### eth_call_by_timestamp + +The [`eth_call_by_timestamp`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#timestamp-and-block-id-hints-in-eth_call_by_timestamp){target=\_blank} query is similar to a standard `eth_call` but targets a specific timestamp instead of a block ID. This is useful for retrieving on-chain data based on a precise point in time, especially for correlating information across different chains. + +The query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block. + +### eth_call_with_finality + +The [`eth_call_with_finality`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#desired-finality-in-eth_call_with_finality){target=\_blank} query type functions like a standard `eth_call`, but with an added critical assurance: it will only return the query results once the specified block has reached a designated level of finality on its chain. + +You can specify one of two finality levels for your query: + +- **Finalized** - indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain +- **Safe** - refers to a block considered highly unlikely to be reorganized, offering a substantial degree of confidence, though the network's consensus may not fully finalize it + +!!! note + If the target blockchain does not natively support or recognize the safe finality tag, requesting safe finality will be treated as a request for finalized finality instead. + +### sol_account + +The [`sol_account`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana-queries){target=\_blank} query reads on-chain data for one or more specified accounts on the Solana blockchain. This functionality is similar to using Solana's native [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} RPC method, enabling you to retrieve information for multiple accounts simultaneously + +### sol_pda + +The [`sol_pda`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana_queries){target=\_blank} query reads data for one or more Solana [Program Derived Addresses](https://www.anchor-lang.com/docs/pdas){target=\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data. + +This is particularly useful for accessing multiple PDAs owned by a specific program or for verifying Solana PDA derivations on another blockchain, such as how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-networks/ +--- BEGIN CONTENT --- +--- +title: Queries Supported Networks +description: Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. +categories: Queries +--- + +# Supported Networks + +This page provides a quick reference for chains supported by Wormhole Queries, including each chain's Wormhole chain ID and the level of support for key methods: [`eth_call`](/docs/products/queries/reference/supported-methods/#eth_call){target=\_blank}, [`eth_call_by_timestamp`](/docs/products/queries/reference/supported-methods/#eth_call_by_timestamp){target=\_blank}, and [`eth_call_with_finality`](/docs/products/queries/reference/supported-methods/#eth_call_with_finality){target=\_blank}. + +The **Expected History** column shows how much recent state data is typically available for querying, though this can vary depending on the chain and the configuration of each Guardian node. + +The support shown in the table reflects what has been confirmed through testing. However, query success ultimately depends on whether the underlying call can be executed on each Guardian’s RPC node. + +For example, many chains use a fork of [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which by default retains 128 blocks of state in memory (unless archive mode is enabled). On Ethereum mainnet, this covers around 25 minutes of history—but on faster chains like Optimism, it may span only about three minutes. While Guardian nodes are expected to have access to recent state, there are currently no guarantees on how far back historical data is available. + +## Mainnet + +| Chain | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History | +|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:| +| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | +| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | +| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | +| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | +| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | +| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | +| Karura | 11 | ✅ | ✅ | ✅ | archive | +| Acala | 12 | ✅ | ✅ | ✅ | archive | +| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | +| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks | +| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks | +| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | +| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | +| Base | 30 | ✅ | ✅ | ✅ | archive | + +ℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -1202,6 +1303,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -1821,28 +2229,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -2737,75 +3145,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -2919,6 +3259,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -2996,6 +3729,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -3052,6 +3786,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -3111,6 +3846,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -3167,6 +3903,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -3268,6 +4005,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3455,95 +4193,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index d9399a735..66111fdd8 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -79,6 +79,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -135,6 +136,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -194,6 +196,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -250,6 +253,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -351,6 +355,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -538,95 +543,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 6f9497459..121f782cd 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -925,6 +925,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -1544,28 +1851,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -2460,75 +2767,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -2642,6 +2881,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -2719,6 +3351,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -2775,6 +3408,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -2834,6 +3468,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -2890,6 +3525,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -2991,6 +3627,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3178,95 +3815,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 15c00e58e..de536c699 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -18,6 +18,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] ## Full content for each doc page @@ -546,6 +547,121 @@ This example solver does NOT do the following: - Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Settlement Overview +description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. +categories: Settlement, Transfer +--- + +# Settlement Overview + +Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. + +Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. + +It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. + +## Key Features + +- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. +- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. +- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. +- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. + +## How It Works + +At the core of Settlement are two components: + +- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. +- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. + +Settlement leverages the following three integrated protocols. + +### Mayan Swift + +Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. + +The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. + +1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. +2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. +3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. + +```mermaid +sequenceDiagram + participant User + participant Solver_ARB as Solver (Arbitrum) + participant Escrow + participant Wormhole + participant Solver_SOL as Solver (Solana) + participant Aggregator + + Note over User,Aggregator: User has ARB and wants WIF + + User->>Solver_ARB: Submit intent (ARB → WIF) + Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH + Escrow-->>Wormhole: Emits VAA + Wormhole-->>Solver_SOL: Delivers VAA + Solver_SOL->>Aggregator: Releases SOL and swaps to WIF + Aggregator->>Solver_SOL: Receives WIF + Solver_SOL->>User: Sends WIF + User-->>Wormhole: Emits final VAA + Wormhole-->>Escrow: Confirms receipt + Escrow->>Solver_ARB: Releases ETH to solver +``` + +### Liquidity Layer + +The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. + +### Mayan MCTP + +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. + +### One Integration, Three Ways + +Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. + +By default, Settlement integrates all three: + +- The SDK automatically resolves the best route for each transfer. +- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. +- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. + +Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. + +To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. + +## Use Cases + +- **Cross-Chain Perpetuals** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + +- **Bridging Intent Library** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + +- **Multichain Prediction Markets** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + +## Next Steps + +Start building with Settlement or dive deeper into specific components: + +- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. +- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -920,6 +1036,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -1539,28 +1962,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -2455,75 +2878,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -2637,6 +2992,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -2714,6 +3462,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -2770,6 +3519,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -2829,6 +3579,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -2885,6 +3636,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -2986,6 +3738,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3173,95 +3926,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 58620a15c..a46bd4eaa 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -16,6 +16,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md [type: other] ## Full content for each doc page @@ -907,6 +908,399 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ --- BEGIN CONTENT --- --- @@ -982,18 +1376,7 @@ Please refer to the complete `WormholeRelayerSDK.sol` file below for further det ???- code "`WormholeRelayerSDK.sol`" ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/constants/Chains.sol"; -import "wormhole-sdk/Utils.sol"; - -import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; -import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; -import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; -import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; + code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol ``` ### Base Contract Overview @@ -1003,87 +1386,20 @@ The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/bl - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions ```solidity - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:22:28 ``` - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources ```solidity - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:45:54 ``` These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. ???- code "`Base.sol`" ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/Utils.sol"; - -abstract contract Base { - IWormholeRelayer public immutable wormholeRelayer; - IWormhole public immutable wormhole; - - address registrationOwner; - mapping(uint16 => bytes32) registeredSenders; - - constructor(address _wormholeRelayer, address _wormhole) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - wormhole = IWormhole(_wormhole); - registrationOwner = msg.sender; - } - - modifier onlyWormholeRelayer() { - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } - - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } - - /** - * Sets the registered address for 'sourceChain' to 'sourceAddress' - * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid - * - * Assumes only one sender per chain is valid - * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) - */ - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -} + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol ``` ### Interface for Cross-Chain Messages @@ -1118,32 +1434,7 @@ This section covers cross-chain messaging and token transfers and shows how to u To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; - -contract CrossChainSender is Base { - constructor( - address _wormholeRelayer, - address _wormhole - ) Base(_wormholeRelayer, _wormhole) {} - - function sendMessage( - bytes memory message, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Register sender and send message through WormholeRelayer - setRegisteredSender(targetChain, msg.sender); - onlyWormholeRelayer().sendPayloadToEvm( - targetChain, - address(targetAddress), - message, - 0, - 500_000 - ); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol ``` This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. @@ -1153,26 +1444,7 @@ This contract extends `Base.sol` and allows sending cross-chain messages securel The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenSender is TokenSender { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenSender(_wormholeRelayer, _wormhole) {} - - function sendToken( - address token, - uint256 amount, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Send tokens across chains - transferTokenToTarget(token, amount, targetChain, targetAddress); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol ``` In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. @@ -1182,28 +1454,7 @@ In this example, `TokenSender` initiates a token transfer to another chain. The To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenReceiver is TokenReceiver { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenReceiver(_wormholeRelayer, _wormhole) {} - - // Function to handle received tokens from another chain - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable override { - // Process the received tokens here - receiveTokens(payload); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol ``` In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. @@ -1595,6 +1846,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -2214,28 +2772,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -3130,75 +3688,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -3312,6 +3802,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -3389,6 +4272,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -3445,6 +4329,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -3504,6 +4389,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -3560,6 +4446,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -3661,6 +4548,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3848,95 +4736,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index c5f7a7911..df41344f1 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -15,9 +15,11 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md [type: other] ## Full content for each doc page @@ -313,6 +315,288 @@ The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardia A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Payload Structure +description: Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. +categories: Token-Bridge, Transfers +--- + +# Message and Payload Structure + +To enable secure and flexible cross-chain token transfers, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} defines a set of standardized payloads. These payloads are embedded in [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} and processed by bridge contracts on the source and destination chains. Each payload has a unique format and serves a specific role in the lifecycle of token bridging. + +This page outlines each payload type in detail. + +## Transfer + +The `Transfer` payload (ID = `1`) is the core mechanism for moving tokens across chains. It is emitted when a user locks or burns tokens on the source chain. On the destination chain, it instructs the bridge to either mint a wrapped token or release native tokens from custody. + +```text +PayloadID uint8 = 1 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +Fee uint256 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `1`, indicating a `Transfer` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals for consistency across all chains. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Left-zero-padded if shorter than 32 bytes. + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `Fee` ++"uint256"++ + + Amount of tokens that the user is willing to pay as relayer fee. Must be less than Amount. Optional and can be claimed by relayers who submit the VAA on the target chain. + + +To keep `Transfer` messages small, they don't carry all the token's metadata. However, this means that before a token can be transferred to a new chain for the first time, the metadata needs to be bridged, and the wrapped asset needs to be created. Metadata, in this case, includes the number of decimals, which is a core requirement for instantiating a token. + +## AssetMeta + +Before a token can be transferred to a new chain for the first time, its metadata must be attested using the `AssetMeta` payload (ID = `2`). This ensures proper decimal precision and display. + +```text +PayloadID uint8 = 2 +TokenAddress [32]uint8 +TokenChain uint16 +Decimals uint8 +Symbol [32]uint8 +Name [32]uint8 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `2`, indicating a `AssetMeta` operation. + + --- + + `TokenAddress` ++"[32]uint8"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `Decimals` ++"uint8"++ + + Number of decimals the token uses on its native chain (not truncated to 8). + + --- + + `Symbol` ++"[32]uint8"++ + + Symbol of the token, UTF-8 encoded and padded to 32 bytes. + + --- + + `Name` ++"[32]uint8"++ + + Name of the token, UTF-8 encoded and padded to 32 bytes. + +## TransferWithPayload + +The `TransferWithPayload` payload (ID = `3`) extends the standard token transfer by allowing developers to include arbitrary data. This enables interactions with destination chain smart contracts, such as triggering swaps or staking. + +```text +PayloadID uint8 = 3 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +FromAddress bytes32 +Payload bytes +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `3`, indicating a `TransferWithPayload` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `FromAddress` ++"bytes32"++ + + Address of the sender on the source chain. + + --- + + `Payload` ++"bytes"++ + + Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic. + + +Unlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly. + +## RegisterChain + +The `RegisterChain` governance payload (Action ID = `1`) registers a Token Bridge emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers. + +```text +Module [32]byte +Action uint8 = 1 +ChainId uint16 + +EmitterChainID uint16 +EmitterAddress [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier. Left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `1`, indicating a `RegisterChain` operation. + + --- + + `ChainID` ++"uint16"++ + + The chain where this governance action should be applied. `0` is a valid value for all chains + + --- + + `EmitterChainID` ++"uint16"++ + + Chain ID of the registered emitter. + + --- + + `EmitterAddress` ++"[32]uint8"++ + + Address of the registered emitter, left-zero-padded if shorter than 32 bytes. + +This payload can only be emitted by the Wormhole governance contract, ensuring that each chain accepts messages only from one verified bridge emitter per remote chain. + +## UpgradeContract + +The `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the Token Bridge contract on a specific chain. + +```text +Module [32]byte +Action uint8 = 2 +ChainId uint16 + +NewContract [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier, left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `2`, indicating an `UpgradeContract` operation. + + --- + + `ChainID` ++"uint16"++ + + The target chain where the governance action should be applied. + + --- + + `NewContract` ++"[32]uint8"++ + + Address of the new Token Bridge contract, left-zero-padded to 32 bytes. + +This message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security. + +## Summary of Payload Structure + +| Payload Type | ID | Purpose | Who Emits It | +|-----------------------|---------------|------------------------------------------------------------------------|------------------------| +| `Transfer` | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination | Token Bridge contract | +| `AssetMeta` | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer | Token Bridge contract | +| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution | Token Bridge contract | +| `RegisterChain` | Action `1` | Registers a verified Token Bridge emitter for a foreign chain | Wormhole governance | +| `UpgradeContract` | Action `2` | Upgrades the Token Bridge contract on a specific chain | Wormhole governance | +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ --- BEGIN CONTENT --- --- @@ -325,7 +609,7 @@ categories: Token-Bridge, Transfer ## Introduction -The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. +The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. @@ -337,7 +621,7 @@ Cross-chain token transfers using the Token Bridge follow these steps: The transfer begins when a user calls the Token Bridge contract on the source chain: - **Wrapped tokens**: The token is burned. - - **Native tokens**: The token is locked in the contract. + - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. 2. **Transfer Message Publication** The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. @@ -357,18 +641,48 @@ Cross-chain token transfers using the Token Bridge follow these steps: After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: - **Wrapped tokens**: A wrapped representation of the original token is minted. - - **Native tokens**: The original token is released to the recipient. + - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. + +Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. ```mermaid sequenceDiagram - participant User - participant TokenBridgeSrc as Token Bridge
(Source Chain) - participant CoreSrc as Core Contract
(Source Chain) + participant Alice as Alice + participant TokenBridgeEth as Token Bridge Ethereum
(Source Chain) + participant CoreEth as Core Contract Ethereum
(Source Chain) participant Guardians - participant TokenBridgeDst as Token Bridge
(Destination Chain) - participant CoreDst as Core Contract
(Destination Chain) + participant TokenBridgeSol as Token Bridge Solana
(Destination Chain) + participant CoreSol as Core Contract Solana
(Destination Chain) - User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + Alice->>TokenBridgeEth: Initiate ETH transfer
(lock ETH) + TokenBridgeEth->>CoreEth: Publish transfer message + CoreEth-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeSol: Relayer submits VAA + else Manual VAA submission + Alice->>Guardians: Retrieve VAA + Alice->>TokenBridgeSol: Submit VAA + end + + TokenBridgeSol->>CoreSol: Verify VAA + CoreSol-->>TokenBridgeSol: VAA verified + TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +``` + +Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. + +```mermaid +sequenceDiagram + participant User as Alice + participant TokenBridgeSrc as Token Bridge Solana
(Source Chain) + participant CoreSrc as Core Contract Solana
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge Ethereum
(Destination Chain) + participant CoreDst as Core Contract Ethereum
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn wrapped ETH) TokenBridgeSrc->>CoreSrc: Publish message CoreSrc-->>Guardians: Emit message event Guardians->>Guardians: Sign and publish VAA @@ -382,9 +696,10 @@ sequenceDiagram TokenBridgeDst->>CoreDst: Verify VAA CoreDst-->>TokenBridgeDst: VAA verified - TokenBridgeDst-->>User: Complete transfer (mint/release token) + TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) ``` + ## Automatic vs. Manual Transfers The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: @@ -815,6 +1130,89 @@ Now that you've completed a manual multichain token transfer, explore these guid - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer +--- + +# Token Bridge Overview + +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. + +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. + +## Key Features + +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: + +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity + +## How It Works + +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: + +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain + +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. + +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana + + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message + + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) + + Solana->>Alice: Deliver wrapped ETH on Solana +``` + +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. + +## Use Cases + +Here are key use cases that highlight the power and versatility of the Token Bridge. + +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + +- **Tokenized Gaming Rewards** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + +- **Multichain DeFi Arbitrage** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + +## Next Steps + +If you are looking for more guided practice, take a look at: + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -1189,6 +1587,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -1808,28 +2513,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -2724,75 +3429,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -2906,6 +3543,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -2983,6 +4013,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -3039,6 +4070,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -3098,6 +4130,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -3154,6 +4187,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -3255,6 +4289,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -3442,95 +4477,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index 3d126e2fc..d252e3d38 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -28,14 +28,16 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] @@ -45,6 +47,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] @@ -52,8 +55,10 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md [type: other] ## Full content for each doc page @@ -351,7 +356,7 @@ contract CircleIntegration is // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` // should be the target contract (or wallet) composing on this contract. - (uint64 nonce, uint256 amountReceived) = _transferTokens( + (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}( transferParams.token, transferParams.amount, transferParams.targetChain, @@ -4090,6 +4095,307 @@ The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardia A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with CCTP +description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. +categories: Transfer +--- + +# Get Started with CCTP + +## Introduction + +[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. + +You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} + +This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir cctp-bridge + cd cctp-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a CCTP Transfer + +This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. + +Start by defining utility functions for signer and token setup: + +1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: + + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: + + ```ts title="transfer.ts" + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helper'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Get signer from local key + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; + + const automatic = false; + + // Create the circleTransfer transaction (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + const quote = await CircleTransfer.quoteTransfer( + sendChain, + rcvChain, + xfer.transfer + ); + console.log('Quote: ', quote); + + // Step 1: Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Step 2: Wait for Circle Attestation (VAA) + const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); + + // Step 3: Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); + + process.exit(0); +})(); + ``` + +3. Run the script to execute the transfer: + + ```bash + npx tsx transfer.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx transfer.ts +Starting Transfer +Started Transfer: + [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', + '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] + +Waiting for Attestation +Retrying Circle:GetAttestation, attempt 0/60 +Retrying Circle:GetAttestation, attempt 1/60 + +Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] + +Completing Transfer +Completed Transfer: + [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] + +
+ +To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: + + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: CCTP Bridge with Wormhole +description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. +categories: Transfer +--- + +# CCTP with Wormhole Overview + +The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. + +## Key Features + +- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. +- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. +- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. +- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. +- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. +- **Gas payment**: Covering destination gas in automated vs. manual transfers. + - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. + - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. + +## How It Works + +This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. + +1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. + +2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. + +3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. + +4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. + +5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. + +```mermaid +sequenceDiagram + participant User as Alice + participant SourceChain as Circle Bridge
on Ethereum + participant Circle + participant Guardians as Wormhole Guardians + participant Relayer + participant DestinationChain as Circle Bridge
on Avalanche + + User->>SourceChain: Submit transfer
(100 USDC to Avalanche) + SourceChain->>Circle: Initiate a burn + Circle->>Circle: Burn USDC and provide attestation + SourceChain->>Guardians: Emit Wormhole message (transfer metadata) + Guardians->>Guardians: Sign message and produce VAA + Relayer->>Guardians: Fetch signed VAA + Relayer->>Circle: Fetch Circle burn attestation + Relayer->>DestinationChain: Submit VAA and
attestation + DestinationChain->>Circle: Verify Circle attestation + Circle->>User: Mint USDC to Alice +``` + +!!! note + For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. + +## Use Cases + +Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: + +- **USDC Payments Across Chains** + - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. + - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. + +- **USDC-Powered Multichain Settlement** + - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. + +## Next Steps + +Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: + +- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. +- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- @@ -5427,6 +5733,72 @@ wormholeConnectHosted(container, { In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/overview/ +--- BEGIN CONTENT --- +--- +title: Wormhole Connect +description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. +categories: Connect, Transfer +--- + +# Connect Overview + +With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. + +## Key Features + +Wormhole connect's notable features include: + +- **In-app multichain transfers**: Bridge assets without leaving your app. +- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. +- **Customizable UI**: Style the bridge interface to match your brand. +- **Optional destination gas**: Provide gas for initial transactions on the target chain. +- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. + +Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. + +## How It Works + +When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: + +1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. +2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). +3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. +6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. +7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. + +!!! tip + If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. + +## Use Cases + +Here are some key use cases that highlight the power and versatility of Connect: + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains + - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + +- **Cross-Chain Payment Widgets** + + - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + +- **Web3 Game Asset Transfers** + + - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + +## Next Steps + +Add Connect to your app with these key setup steps: + +[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ --- BEGIN CONTENT --- --- @@ -5514,195 +5886,6 @@ This route appears if all of the following conditions are satisfied: - The relayer accepts the selected token to swap into the gas token --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ ---- BEGIN CONTENT --- ---- -title: Get Started with Messaging -description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. -categories: Messaging, Transfer ---- - -# Get Started with Messaging - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} - -## Introduction - -Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. - -## Prerequisites - -Before you begin, make sure you have the following: - -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key -- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} -- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} -- Wallet private key - -## Install and Set Up Project - -1. Clone the demo repository and navigate to the project directory: - - ```bash - git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git - cd demo-wormhole-messaging - ``` - -2. Use the following commands to install Foundry and project dependencies: - - ```bash - npm install - ``` - -3. Use Foundry's Forge to compile the contracts in the repository: - - ```bash - forge build - ``` - - You will see terminal output similar to the following, confirming the contracts were compiled successfully: - -
-forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
- -4. Run tests to ensure everything is functioning correctly before deployment: - - ```bash - forge test - ``` - - You will see passing results for all test cases in the terminal output: - -
-forge test -[⠊] Compiling... -No files changed, compilation skipped -Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest -[PASS] testDeployment() (gas: 13544) -[PASS] testReceiveMessage() (gas: 22579) -[PASS] testSendMessage() (gas: 22719) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) -Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) - -
- -## Prepare for Contract Deployment - -This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: - -- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji -- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores - -The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. - -### Encrypt Private Key - -Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. - -1. Create a Foundry keystore to encrypt your wallet private key using the following command: - - ```bash - cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY - ``` - -2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: - - ```bash - Enter password: INSERT_DECRYPTION_PASSWORD - ``` - -3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required - -## Deploy Sender Contract - -Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: - -1. Run the deployment script command in your terminal: - - ```bash - npm run deploy:sender - ``` - -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - -
-npm run deploy:sender -Enter keystore password: XXXXXXXXXXXX -MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 - -
- - The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. - -## Deploy Receiver Contract - -Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: - -1. Run the deployment script command in your terminal: - - ```bash - npm run deploy:receiver - ``` - -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - -
-npm run deploy:receiver -Enter keystore password: XXXXXXXXXXXX -MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 -Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) - -
- - - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file - - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji - -## Send Your First Message - -Follow these steps to use your deployed contracts and send your first message: - -1. Run the `sendMessage.ts` script using the following command: - - ```bash - npm run send:message - ``` - -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: - -
-npm run send:message -Enter keystore password: XXXXXXXXXXXX -Transaction sent, waiting for confirmation... -... -Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 -You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET - -
- -4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: - - ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) - -Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. - -## Next Steps - - ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- @@ -6541,8 +6724,13 @@ categories: NTT, Transfer This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. + +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. + ## Prerequisites Before deploying NTT on Solana, ensure you have the following: @@ -6668,14 +6856,13 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. - ### Generate an NTT Program Key Pair Create a unique key pair for the NTT program: - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +```bash +solana-keygen grind --starts-with ntt:1 --ignore-case +``` ### Set Mint Authority @@ -6794,6 +6981,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -6986,15 +7181,98 @@ Enter a new value to adjust limits and click **Update**. The changes will take e ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ --- BEGIN CONTENT --- --- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. categories: NTT, Transfer --- -# NTT CLI Commands +## Native Token Transfers Overview + +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. + +## Key Features + +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps + + +## Deployment Models + +NTT offers two operational modes for your existing tokens: + +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token + +## Supported Token Standards + +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. + +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. + +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. + +## Deployment Process + +Here's a breakdown of the key steps involved when deploying NTT: + +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed + +## Use Cases + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + +- **Borrowing and Lending Across Chains** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + +- **Gas Abstraction** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + +- **Cross-Chain Payment Widgets** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + +- **Cross-Chain Staking** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + +## Next Steps + +Follow these steps to get started with NTT: + +[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +--- BEGIN CONTENT --- +--- +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer +--- + +# NTT CLI Commands ## Introduction @@ -7712,6 +7990,121 @@ This example solver does NOT do the following: - Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Settlement Overview +description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. +categories: Settlement, Transfer +--- + +# Settlement Overview + +Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. + +Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. + +It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. + +## Key Features + +- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. +- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. +- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. +- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. + +## How It Works + +At the core of Settlement are two components: + +- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. +- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. + +Settlement leverages the following three integrated protocols. + +### Mayan Swift + +Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. + +The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. + +1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. +2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. +3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. + +```mermaid +sequenceDiagram + participant User + participant Solver_ARB as Solver (Arbitrum) + participant Escrow + participant Wormhole + participant Solver_SOL as Solver (Solana) + participant Aggregator + + Note over User,Aggregator: User has ARB and wants WIF + + User->>Solver_ARB: Submit intent (ARB → WIF) + Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH + Escrow-->>Wormhole: Emits VAA + Wormhole-->>Solver_SOL: Delivers VAA + Solver_SOL->>Aggregator: Releases SOL and swaps to WIF + Aggregator->>Solver_SOL: Receives WIF + Solver_SOL->>User: Sends WIF + User-->>Wormhole: Emits final VAA + Wormhole-->>Escrow: Confirms receipt + Escrow->>Solver_ARB: Releases ETH to solver +``` + +### Liquidity Layer + +The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. + +### Mayan MCTP + +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. + +### One Integration, Three Ways + +Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. + +By default, Settlement integrates all three: + +- The SDK automatically resolves the best route for each transfer. +- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. +- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. + +Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. + +To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. + +## Use Cases + +- **Cross-Chain Perpetuals** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + +- **Bridging Intent Library** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + +- **Multichain Prediction Markets** + + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + +## Next Steps + +Start building with Settlement or dive deeper into specific components: + +- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. +- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ --- BEGIN CONTENT --- --- @@ -7724,7 +8117,7 @@ categories: Token-Bridge, Transfer ## Introduction -The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. +The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. @@ -7736,7 +8129,7 @@ Cross-chain token transfers using the Token Bridge follow these steps: The transfer begins when a user calls the Token Bridge contract on the source chain: - **Wrapped tokens**: The token is burned. - - **Native tokens**: The token is locked in the contract. + - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. 2. **Transfer Message Publication** The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. @@ -7756,18 +8149,48 @@ Cross-chain token transfers using the Token Bridge follow these steps: After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: - **Wrapped tokens**: A wrapped representation of the original token is minted. - - **Native tokens**: The original token is released to the recipient. + - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. + +Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. ```mermaid sequenceDiagram - participant User - participant TokenBridgeSrc as Token Bridge
(Source Chain) - participant CoreSrc as Core Contract
(Source Chain) + participant Alice as Alice + participant TokenBridgeEth as Token Bridge Ethereum
(Source Chain) + participant CoreEth as Core Contract Ethereum
(Source Chain) participant Guardians - participant TokenBridgeDst as Token Bridge
(Destination Chain) - participant CoreDst as Core Contract
(Destination Chain) + participant TokenBridgeSol as Token Bridge Solana
(Destination Chain) + participant CoreSol as Core Contract Solana
(Destination Chain) - User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + Alice->>TokenBridgeEth: Initiate ETH transfer
(lock ETH) + TokenBridgeEth->>CoreEth: Publish transfer message + CoreEth-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeSol: Relayer submits VAA + else Manual VAA submission + Alice->>Guardians: Retrieve VAA + Alice->>TokenBridgeSol: Submit VAA + end + + TokenBridgeSol->>CoreSol: Verify VAA + CoreSol-->>TokenBridgeSol: VAA verified + TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +``` + +Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. + +```mermaid +sequenceDiagram + participant User as Alice + participant TokenBridgeSrc as Token Bridge Solana
(Source Chain) + participant CoreSrc as Core Contract Solana
(Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge Ethereum
(Destination Chain) + participant CoreDst as Core Contract Ethereum
(Destination Chain) + + User->>TokenBridgeSrc: Initiate transfer
(burn wrapped ETH) TokenBridgeSrc->>CoreSrc: Publish message CoreSrc-->>Guardians: Emit message event Guardians->>Guardians: Sign and publish VAA @@ -7781,9 +8204,10 @@ sequenceDiagram TokenBridgeDst->>CoreDst: Verify VAA CoreDst-->>TokenBridgeDst: VAA verified - TokenBridgeDst-->>User: Complete transfer (mint/release token) + TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) ``` + ## Automatic vs. Manual Transfers The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: @@ -7922,6 +8346,89 @@ Updating the metadata (such as the token image, name, or symbol) of a wrapped to To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer +--- + +# Token Bridge Overview + +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. + +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. + +## Key Features + +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: + +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity + +## How It Works + +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: + +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain + +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. + +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana + + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message + + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) + + Solana->>Alice: Deliver wrapped ETH on Solana +``` + +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. + +## Use Cases + +Here are key use cases that highlight the power and versatility of the Token Bridge. + +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + +- **Tokenized Gaming Rewards** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + +- **Multichain DeFi Arbitrage** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + +## Next Steps + +If you are looking for more guided practice, take a look at: + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +--- END CONTENT --- + ## Basics Concepts [shared: true] The following section contains foundational documentation shared across all Wormhole products. @@ -8296,6 +8803,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -8915,28 +9729,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -9831,75 +10645,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -10013,6 +10759,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -10090,6 +11229,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -10146,6 +11286,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -10205,6 +11346,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -10261,6 +11403,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -10362,6 +11505,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -10549,95 +11693,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. - -## Supported Environments +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### Token Bridge -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 4baf787ce..71d05020d 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -16,6 +16,8 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md [type: other] @@ -910,6 +912,554 @@ To manually submit a VAA (Verifiable Action Approval) to a destination chain, fo Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the TypeScript SDK +description: Follow this guide to install the Wormhole TypeScript SDK, initialize a Wormhole instance, and add the platforms your integration supports. +categories: Typescript-SDK +--- + +# Get Started with the TypeScript SDK + +## Introduction + +The Wormhole TypeScript SDK provides a unified, type-safe interface for building cross-chain applications. It is a foundational toolkit that supports interaction with core Wormhole protocols, including Native Token Transfers, Token Bridge, CCTP, and Settlement, giving developers a consistent API across multiple chains. + +This guide helps you install the SDK, initialize a `Wormhole` instance to support your desired network and blockchain platforms, and return chain-specific information to verify successful initialization. + +If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: + + ```bash + npm install --save-dev tsx typescript @types/node + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +## Install the SDK + +To install the Wormhole TypeScript SDK, use the following command: + +```bash +npm install @wormhole-foundation/sdk +``` + +This package combines all the individual packages to make setup easier. + +You can choose to install a specific set of packages as needed. For example, to install EVM-specific utilities, you can run: + +```bash +npm install @wormhole-foundation/sdk-evm +``` + +??? example "Complete list of individually published packages" + + Platform-Specific Packages + + - `@wormhole-foundation/sdk-evm` + - `@wormhole-foundation/sdk-solana` + - `@wormhole-foundation/sdk-algorand` + - `@wormhole-foundation/sdk-aptos` + - `@wormhole-foundation/sdk-cosmwasm` + - `@wormhole-foundation/sdk-sui` + + --- + + Protocol-Specific Packages + + - Core Protocol + - `@wormhole-foundation/sdk-evm-core` + - `@wormhole-foundation/sdk-solana-core` + - `@wormhole-foundation/sdk-algorand-core` + - `@wormhole-foundation/sdk-aptos-core` + - `@wormhole-foundation/sdk-cosmwasm-core` + - `@wormhole-foundation/sdk-sui-core` + + - Token Bridge + - `@wormhole-foundation/sdk-evm-tokenbridge` + - `@wormhole-foundation/sdk-solana-tokenbridge` + - `@wormhole-foundation/sdk-algorand-tokenbridge` + - `@wormhole-foundation/sdk-aptos-tokenbridge` + - `@wormhole-foundation/sdk-cosmwasm-tokenbridge` + - `@wormhole-foundation/sdk-sui-tokenbridge` + + - CCTP + - `@wormhole-foundation/sdk-evm-cctp` + - `@wormhole-foundation/sdk-solana-cctp` + - `@wormhole-foundation/sdk-aptos-cctp` + - `@wormhole-foundation/sdk-sui-cctp` + + - Other Protocols + - `@wormhole-foundation/sdk-evm-portico` + - `@wormhole-foundation/sdk-evm-tbtc` + - `@wormhole-foundation/sdk-solana-tbtc` + + --- + + Utility Packages + + - `@wormhole-foundation/sdk-base` + - `@wormhole-foundation/sdk-definitions` + - `@wormhole-foundation/sdk-connect` + + +## Initialize the SDK + +You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. + +1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + +2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; +// Import specific platform modules for the chains you intend to use +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + // Determine the network: "Mainnet", "Testnet", or "Devnet" + const network = 'Testnet'; + + // Initialize the SDK with the chosen network and platform contexts + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); +} + +main().catch((e) => { + console.error('Error initializing Wormhole SDK', e); + process.exit(1); +}); + ``` + +## Fetch Chain Information + +Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. + +1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + const network = 'Testnet'; + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); + + // Example: Get a chain ID and RPC for Solana + const solanaDevnetChain = wh.getChain('Solana'); + console.log( + `Chain ID for Solana Testnet: ${solanaDevnetChain.config.chainId}` + ); + console.log(`RPC for Solana Testnet: ${solanaDevnetChain.config.rpc}`); + + // Example: Get a chain ID for Sepolia (EVM Testnet) + const sepoliaChain = wh.getChain('Sepolia'); + console.log(`Chain ID for Sepolia: ${sepoliaChain.config.chainId}`); + console.log(`RPC for Sepolia: ${sepoliaChain.config.rpc}`); +} + +main().catch((e) => { + console.error( + 'Error initializing Wormhole SDK or fetching chain information:', + e + ); + process.exit(1); +}); + ``` + +2. Run the script with the following command, replacing `INSERT_FILE_NAME` with your file name: + + ```bash + npx tsx INSERT_FILE_NAME + ``` + + You will see terminal output similar to the following: + +
+npx tsx src/main.ts +Initializing Wormhole SDK... +Wormhole SDK Initialized! +Chain ID for Solana Testnet: 1 +RPC for Solana Testnet: https://api.devnet.solana.com +Chain ID for Sepolia: 10002 +RPC for Sepolia: https://ethereum-sepolia.publicnode.com + +
+ +Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and initialized a `Wormhole` instance. Consider the following options to build on what you've accomplished. + +## Next Steps + +- [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) +- [Send a multichain message](TODO: get started messaging) +- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) +- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ --- BEGIN CONTENT --- --- @@ -3846,6 +4396,313 @@ A Spy is a daemon that eavesdrops on the messages passed between Guardians, typi A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
+ +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ --- BEGIN CONTENT --- --- @@ -4465,28 +5322,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -5381,75 +6238,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -5563,6 +6352,399 @@ For more information about submitting to the bug bounty programs, refer to the [ The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); + + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); + + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); + + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } + + process.exit(0); +})(); + ``` + + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. + +3. Run the script using the following command: + + ```bash + npx tsx script/transfer.ts + ``` + +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: + +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
+ +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. +--- END CONTENT --- + ## Reference Concepts [shared: true] The following section contains reference material for Wormhole. @@ -5640,6 +6822,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -5696,6 +6879,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -5755,6 +6939,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -5811,6 +6996,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -5912,6 +7098,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -6099,95 +7286,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### Token Bridge + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ diff --git a/llms-full.txt b/llms-full.txt index f80189007..1e2bea064 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -2062,7 +2062,7 @@ contract CircleIntegration is // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` // should be the target contract (or wallet) composing on this contract. - (uint64 nonce, uint256 amountReceived) = _transferTokens( + (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}( transferParams.token, transferParams.amount, transferParams.targetChain, @@ -5962,7 +5962,220 @@ TODO Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ --- BEGIN CONTENT --- -TODO +--- +title: Get Started with CCTP +description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. +categories: Transfer +--- + +# Get Started with CCTP + +## Introduction + +[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. + +You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} + +This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir cctp-bridge + cd cctp-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a CCTP Transfer + +This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. + +Start by defining utility functions for signer and token setup: + +1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: + + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: + + ```ts title="transfer.ts" + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helper'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Get signer from local key + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; + + const automatic = false; + + // Create the circleTransfer transaction (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + const quote = await CircleTransfer.quoteTransfer( + sendChain, + rcvChain, + xfer.transfer + ); + console.log('Quote: ', quote); + + // Step 1: Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Step 2: Wait for Circle Attestation (VAA) + const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); + + // Step 3: Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); + + process.exit(0); +})(); + ``` + +3. Run the script to execute the transfer: + + ```bash + npx tsx transfer.ts + ``` + + You will see terminal output similar to the following: + +
+npx tsx transfer.ts +Starting Transfer +Started Transfer: + [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', + '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] + +Waiting for Attestation +Retrying Circle:GetAttestation, attempt 0/60 +Retrying Circle:GetAttestation, attempt 1/60 + +Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] + +Completing Transfer +Completed Transfer: + [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] + +
+ +To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: + + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/transfer-usdc/ @@ -5972,7 +6185,85 @@ TODO Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ --- BEGIN CONTENT --- -TODO +--- +title: CCTP Bridge with Wormhole +description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. +categories: Transfer +--- + +# CCTP with Wormhole Overview + +The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. + +## Key Features + +- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. +- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. +- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. +- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. +- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. +- **Gas payment**: Covering destination gas in automated vs. manual transfers. + - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. + - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. + +## How It Works + +This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. + +1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. + +2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. + +3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. + +4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. + +5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. + +```mermaid +sequenceDiagram + participant User as Alice + participant SourceChain as Circle Bridge
on Ethereum + participant Circle + participant Guardians as Wormhole Guardians + participant Relayer + participant DestinationChain as Circle Bridge
on Avalanche + + User->>SourceChain: Submit transfer
(100 USDC to Avalanche) + SourceChain->>Circle: Initiate a burn + Circle->>Circle: Burn USDC and provide attestation + SourceChain->>Guardians: Emit Wormhole message (transfer metadata) + Guardians->>Guardians: Sign message and produce VAA + Relayer->>Guardians: Fetch signed VAA + Relayer->>Circle: Fetch Circle burn attestation + Relayer->>DestinationChain: Submit VAA and
attestation + DestinationChain->>Circle: Verify Circle attestation + Circle->>User: Mint USDC to Alice +``` + +!!! note + For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. + +## Use Cases + +Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: + +- **USDC Payments Across Chains** + - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. + - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. + +- **USDC-Powered Multichain Settlement** + - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. + +## Next Steps + +Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: + +- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. +- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ @@ -8566,7 +8857,68 @@ In this example, the `config` object defines the routes (in this case, using the Doc-Content: https://wormhole.com/docs/products/connect/overview/ --- BEGIN CONTENT --- -TODO +--- +title: Wormhole Connect +description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. +categories: Connect, Transfer +--- + +# Connect Overview + +With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. + +## Key Features + +Wormhole connect's notable features include: + +- **In-app multichain transfers**: Bridge assets without leaving your app. +- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. +- **Customizable UI**: Style the bridge interface to match your brand. +- **Optional destination gas**: Provide gas for initial transactions on the target chain. +- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. + +Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. + +## How It Works + +When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: + +1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. +2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). +3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. +6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. +7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. + +!!! tip + If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. + +## Use Cases + +Here are some key use cases that highlight the power and versatility of Connect: + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains + - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + +- **Cross-Chain Payment Widgets** + + - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + +- **Web3 Game Asset Transfers** + + - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + +## Next Steps + +Add Connect to your app with these key setup steps: + +[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ @@ -8845,189 +9197,307 @@ Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- title: Get Started with Messaging -description: Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. -categories: Messaging, Transfer +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK --- # Get Started with Messaging -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. -## Introduction +## Prerequisites -Wormhole's messaging protocol simplifies sending data, triggering events, and initiating transactions across blockchain networks. This guide demonstrates how to configure and deploy contracts to send messages from Avalanche Fuji to Celo Alfajores. +Before you begin, ensure you have the following: -## Prerequisites +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions -Before you begin, make sure you have the following: +## Configure Your Messaging Environment -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts and encrypting your private key -- [Testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} -- [Testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} -- Wallet private key +1. Create a directory and initialize a Node.js project: -## Install and Set Up Project + ```bash + mkdir core-message + cd core-message + npm init -y + ``` -1. Clone the demo repository and navigate to the project directory: +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: ```bash - git clone https://github.com/wormhole-foundation/demo-wormhole-messaging.git - cd demo-wormhole-messaging + npm install --save-dev tsx typescript @types/node ethers ``` -2. Use the following commands to install Foundry and project dependencies: +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: ```bash - npm install + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } ``` -3. Use Foundry's Forge to compile the contracts in the repository: +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: ```bash - forge build + npm install @wormhole-foundation/sdk ``` - You will see terminal output similar to the following, confirming the contracts were compiled successfully: - -
-forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
- -4. Run tests to ensure everything is functioning correctly before deployment: +5. Create a new file named `main.ts`: ```bash - forge test + touch main.ts ``` - You will see passing results for all test cases in the terminal output: - -
-forge test -[⠊] Compiling... -No files changed, compilation skipped -Ran 3 tests for test/CrossChainMessagingTest.sol:CrossChainMessagingTest -[PASS] testDeployment() (gas: 13544) -[PASS] testReceiveMessage() (gas: 22579) -[PASS] testSendMessage() (gas: 22719) -Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.66ms (3.25ms CPU time) -Ran 1 test suite in 124.80ms (5.66ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) - -
- -## Prepare for Contract Deployment - -This project relies on two [Wormhole Solidity SDK-based](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} smart contracts: - -- **MessageSender.sol** - sends a message to the target chain. You will deploy this contract to Avalanche Fuji -- **MessageReceiver.sol** - receives and logs the message on the target chain. You will deploy this contract to Celo Alfajores +## Construct and Publish Your Message -The `chains.json` configuration defines properties for supported chains, including the Wormhole relayer addresses, RPC URLs, and chain IDs, and provides this information to the deployment scripts when you run them. +1. Open `main.ts` and update the code there as follows: -### Encrypt Private Key - -Foundry supports multiple options for [creating a keystore](https://book.getfoundry.sh/reference/cast/cast-wallet-import){target=\_blank}. This example uses the `--privatekey` option. As long as you have a decryption password to enter when prompted, you can use your preferred options when creating your Foundry keystore. + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; -1. Create a Foundry keystore to encrypt your wallet private key using the following command: +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ - ```bash - cast wallet import CELO_AVAX --privatekey INSERT_PRIVATE_KEY - ``` +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; -2. Enter the password you wish to use to decrypt your private key at the prompt. You will not see the password in the terminal as you type: +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); - ```bash - Enter password: INSERT_DECRYPTION_PASSWORD - ``` + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; -3. Select return to save your password, and you will see a success message confirming that the keystore was saved successfully. Keep this password. You will be prompted to enter it in the terminal when a wallet signature is required + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } -## Deploy Sender Contract + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } -Follow these steps to deploy `MessageSender.sol` to Avalanche Fuji: + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } -1. Run the deployment script command in your terminal: + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); - ```bash - npm run deploy:sender - ``` + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; -2. Enter your Foundry keystore password in the terminal when prompted + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); -3. You will see terminal output similar to the following: + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); -
-npm run deploy:sender -Enter keystore password: XXXXXXXXXXXX -MessageSender deployed to: 0x32fDaD190eC54578713cEFB1787AfE688eab4420 - -
+ // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); - The address you see in your terminal is the Avalanche Fuji address for your deployed sender contract. Your deployed contract addresses are also output to the `deployedContracts.json` file. + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; -## Deploy Receiver Contract + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); -Follow these steps to deploy `MessageReceiver.sol` to Celo Alforjes: + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); -1. Run the deployment script command in your terminal: + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} - ```bash - npm run deploy:receiver +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +});
``` -2. Enter your Foundry keystore password in the terminal when prompted + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. -3. You will see terminal output similar to the following: - -
-npm run deploy:receiver -Enter keystore password: XXXXXXXXXXXX -MessageReceiver deployed to: 0x4Ed1F630c5EbB7A7913aF18052b1A636dA12Eb05 -Registered MessageSender (0x32fDaD190eC54578713cEFB1787AfE688eab4420) for Avalanche chain (6) - -
- - - The Celo Alforjes address for your deployed receiver contract. Your deployed contract addresses are also output to the `deployedContracts.json` file - - Confirmation that a `MessageSender` contract is now registered as authorized to send messages to your receiver contract. This address should match the sender contract you deployed to Avalanche Fuji - -## Send Your First Message - -Follow these steps to use your deployed contracts and send your first message: - -1. Run the `sendMessage.ts` script using the following command: +2. Run the script using the following command: ```bash - npm run send:message + npx tsx main.ts ``` -2. Enter your Foundry keystore password in the terminal when prompted - -3. You will see terminal output similar to the following: + You will see terminal output similar to the following:
-npm run send:message -Enter keystore password: XXXXXXXXXXXX -Transaction sent, waiting for confirmation... -... -Message sent! Transaction hash: 0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54 -You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/0xeb922bfe66ad38c9ed582a80038ba0687df4abf55ade04e6d1e102cd8cec8a54?network=TESTNET +npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +-----------------------------------------
-4. You can also use the [Celo Alfajores Testnet Explorer](https://alfajores.celoscan.io/){target=\_blank} to view your `MessageReceiver` contract. Select **Events** to see the events emitted by the contract when your message was received. You can use the dropdowns to change **Hex** to **Text** to read the message. It will look similar to the image below: - - ![Contract events on Celo Alfajores Testnet Explorer](/docs/images/products/messaging/get-started/messaging-get-started01.webp) +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages -Congratulations! You've successfully sent and received a message across networks using Wormhole Solidity SDK-based smart contracts. +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. ## Next Steps - +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ @@ -9649,28 +10119,28 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – aggregate multi-chain sources + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - **Gas Abstraction** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/){target=\_blank} – handle native token swaps + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps - **Bridging Intent Library** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - execute user-defined bridging intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – enable tokenized rewards + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards ## Next Steps @@ -12220,128 +12690,33 @@ Congratulations! You've successfully built and deployed a cross-chain token tran - Write deployment scripts to manage and deploy contracts on different networks --- END CONTENT --- -<<<<<<< HEAD -Doc-Content: https://wormhole.com/docs/tutorials/solidity-sdk/ ---- BEGIN CONTENT --- ---- -title: Solidity SDK Tutorials -description: Master cross-chain smart contracts with Wormhole's Solidity SDK. Learn messaging, token transfers, and secure, scalable dApp deployments across blockchains. ---- - -# Solidity SDK - -Expand the reach of your decentralized applications by building smart contracts that can communicate across multiple blockchains. Through these tutorials, you’ll learn to create robust cross-chain contracts, enabling your dApps to tap into global liquidity, diverse functionalities, and a broader user base. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Messaging Contracts** - - --- - - Learn how to build and deploy smart contracts that communicate seamlessly across multiple blockchains. This tutorial walks you through using Wormhole's Solidity SDK to send and receive messages between Avalanche Fuji and Celo Alfajores, helping you master emitter validation, relayer usage, and cross-chain cost management. - - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-contracts/) - -- :octicons-repo-16:{ .lg .middle } **Create Cross-Chain Token Transfer Contracts** - - --- - - Discover how to create a fully functional cross-chain token transfer system using Wormhole's Solidity SDK. This tutorial guides you through token attestation, contract deployment, and secure transfers of ERC-20 tokens between test networks. By the end, you’ll know how to tap into global liquidity and enrich your dApps with seamless multi-chain asset movement. - - [:custom-arrow: Start building](/docs/tutorials/solidity-sdk/cross-chain-token-contracts/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Core Contracts** - - --- - - Dive deeper into Wormhole’s foundational concepts for cross-chain contracts. Discover how messaging, guardians, and VAAs work together to enable secure, scalable dApps. - - [:custom-arrow: Explore Core Contracts](/docs/learn/infrastructure/core-contracts/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/ ---- BEGIN CONTENT --- ---- -title: Wormhole SDK Tutorials -description: Master the Wormhole SDK. Build robust cross-chain dApps with messaging, token bridging, and governance across multiple networks. ---- - -# Wormhole SDK - -The Wormhole SDK provides the essential building blocks for creating robust cross-chain applications. With its developer-friendly libraries, tools, and interfaces, you can quickly integrate Wormhole’s messaging, token transfer, and governance functionalities into your projects. Whether you’re building a simple cross-chain dApp or architecting a complex multi-chain ecosystem, these tutorials will guide you through mastering the SDK and unlocking the full potential of Wormhole’s infrastructure. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Transfer USDC via CCTP** - - --- - - Learn how to move native USDC across chains using Circle’s CCTP and Wormhole’s TypeScript SDK. This tutorial shows you how to streamline transfers with automated attestation and finalization or take complete control with manual steps. Gain the skills to handle seamless USDC bridging, optimize user experience, and improve the reliability of your cross-chain applications. - - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/usdc-via-cctp/) - -- :octicons-repo-16:{ .lg .middle } **Transfer Tokens via the Token Bridge** - - --- - - Learn how to build a versatile cross-chain token transfer application using Wormhole’s TypeScript SDK. This tutorial walks you through leveraging the Token Bridge to securely and efficiently move assets between EVM and non-EVM chains. By the end, you’ll understand how to transfer tokens between networks like Ethereum, Solana, Sui, and beyond, opening the door to an interconnected blockchain ecosystem. - - [:custom-arrow: Start building](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/) - -
- -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Wormhole SDK Documentation** - - --- - - Learn to build cross-chain dApps using the Wormhole SDK. Access detailed guides, reference code, and best practices for robust application development. - - [:custom-arrow: Learn more](/docs/build/toolkit/typescript-sdk/) - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/tokens-via-token-bridge/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ --- BEGIN CONTENT --- --- -title: Transfer Tokens via Token Bridge Tutorial -description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +title: Replace Outdated Signatures in VAAs +description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. --- -# Transfer Tokens via the Token Bridge +# Replace Outdated Signatures in VAAs -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} ## Introduction -This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. +Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. -By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: +However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. - - EVM to EVM (e.g., Ethereum to Avalanche) - - EVM to non-EVM chains (e.g., Ethereum to Solana) - - Non-EVM to EVM chains (e.g., Sui to Avalanche) - - Non-EVM to non-EVM chains (e.g., Solana to Sui) +Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. -Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. +In this tutorial, you'll build a script from scratch to: -At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. +- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} +- Validate its signatures against the latest Guardian set +- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} +- Output a valid VAA ready for submission + +By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. ## Prerequisites @@ -12349,1456 +12724,73 @@ Before you begin, ensure you have the following: - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - Native tokens (testnet or mainnet) in Solana and Sui wallets - - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees -## Supported Chains +## Project Setup -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. +In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. -## Project Setup +1. **Create the project** - set up the directory and navigate into it -In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. + ```bash + mkdir wormhole-scan-api-demo + cd wormhole-scan-api-demo + ``` -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project +2. **Initialize a Node.js project** - generate a `package.json` file ```bash - mkdir native-transfers - cd native-transfers npm init -y ``` -2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control +3. **Set up TypeScript** - create a `tsconfig.json` file ```bash - echo ".env" >> .gitignore + touch tsconfig.json ``` -3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries + Then, add the following configuration: - ```bash - npm install @wormhole-foundation/sdk dotenv tsx + ```json title="tsconfig.json" + { + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} ``` -4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +4. **Install dependencies** - add the required packages ```bash - touch .env + npm install @wormhole-foundation/sdk axios web3 tsx @types/node ``` - Inside the `.env` file, add your private keys. + - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions + - `axios` - makes HTTP requests to the Wormholescan API + - `web3` - interacts with Ethereum transactions and contracts + - `tsx` - executes TypeScript files without compilation + - `@types/node` - provides Node.js type definitions - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" +5. **Create the project structure** - set up the required directories and files + + ```bash + mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts + mkdir -p src/helpers && touch src/helpers/vaaHelper.ts + mkdir -p src/scripts && touch scripts/replaceSignatures.ts ``` - !!! note - Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. + - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures + - **`src/helpers/*`** - contains utility functions + - **`src/scripts/*`** - contains scripts for fetching and replacing signatures -5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays +6. **Set variables** - define key constants in `src/config/constants.ts` - 1. Create the helpers file - - ```bash - mkdir -p src/helpers - touch src/helpers/helpers.ts - ``` - - 2. Open the `helpers.ts` file and add the following code - - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, - TokenId, - isTokenId, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import { config } from 'dotenv'; -config(); - -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; -} - -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} - -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext, - gasLimit?: bigint -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; - - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - const evmSignerOptions = gasLimit ? { gasLimit } : {}; - signer = await ( - await evm() - ).getSigner( - await chain.getRpc(), - getEnv('ETH_PRIVATE_KEY'), - evmSignerOptions - ); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); - break; - case 'Aptos': - signer = await ( - await aptos() - ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); - } - - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - -export async function getTokenDecimals< - N extends 'Mainnet' | 'Testnet' | 'Devnet' ->( - wh: Wormhole, - token: TokenId, - sendChain: ChainContext -): Promise { - return isTokenId(token) - ? Number(await wh.getDecimals(token.chain, token.address)) - : sendChain.config.nativeTokenDecimals; -} - - ``` - - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file - - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers - -## Check and Create Wrapped Tokens - -Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. - -In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. - -### Configure the Wrapped Token Script - -1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory - - ```bash - mkdir -p src/scripts - touch src/scripts/create-wrapped.ts - ``` - -2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions - - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; - ``` - -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support - - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` - - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. - -4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) - - ```typescript - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); - ``` - -5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation - - ```typescript - - ``` - -6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation - - ```typescript - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } - ``` - - If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/tutorials/typescript-sdk/tokens-via-token-bridge/#token-transfers). Otherwise, an attestation must be generated. - -7. **Set up the source chain signer** - the signer creates and submits the attestation transaction - - ```typescript - - ``` - -8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step - - ```typescript - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); - - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); - ``` - -9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure - - ```typescript - console.log('Parsed Messages:', msgs); - - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } - ``` - -10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation - - ```typescript - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); - - const tsx = await signSendWait(destChain, subAttestation, destSigner); - ``` - -11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain - - ```typescript - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } - - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` - - If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. - -??? code "Complete script" - ```typescript - import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; - -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Define the source and destination chains - const srcChain = wh.getChain('ArbitrumSepolia'); - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); - - // Destination chain signer setup - const { signer: destSigner } = await getSigner(destChain, gasLimit); - const tbDest = await destChain.getTokenBridge(); - - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } - - // Source chain signer setup - const { signer: origSigner } = await getSigner(srcChain); - - // Create an attestation transaction on the source chain - const tbOrig = await srcChain.getTokenBridge(); - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); - - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); - - // Retrieve the Wormhole message ID from the attestation transaction - const msgs = await srcChain.parseTransaction(txid); - console.log('Parsed Messages:', msgs); - - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } - - console.log('Token Address: ', vaa.payload.token.address); - - // Submit the attestation on the destination chain - console.log('Attesting asset on destination chain...'); - - const subAttestation = tbDest.submitAttestation( - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); - - const tsx = await signSendWait(destChain, subAttestation, destSigner); - console.log('Transaction hash: ', tsx); - - // Poll for the wrapped asset until it's available - async function waitForIt() { - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } - - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` - -### Run the Wrapped Token Creation - -Once the script is ready, execute it with: - -```bash -npx tsx src/scripts/create-wrapped.ts -``` - -If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. - -## Token Transfers - -In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. - -### Configure Transfer Details - -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. - -1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains - - ```bash - touch src/scripts/native-transfer.ts - ``` - -2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files - - ```typescript - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - ``` - -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support - - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` - -4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them - - ```typescript - const rcvChain = wh.getChain('Solana'); - ``` - -5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains - - ```typescript - const destination = await getSigner(rcvChain); - ``` - -6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object - - ```typescript - - ``` - -7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit - - ```typescript - - ``` - -8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself - - ```typescript - - ``` - - !!! note - Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. - -9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function - - ```typescript - - ``` - -10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` - - ```typescript - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); - ``` - - Finally, we use `process.exit(0);` to close the script once the transfer completes - - ```typescript - })(); - ``` - -### Token Transfer Logic - -This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. - -#### Defining the Token Transfer Function - -The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. - -```typescript -wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic -import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); - - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); - - // Define the amount of tokens to transfer - const amt = '1'; - - // Set automatic transfer to false for manual transfer - const automatic = false; - - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); - - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); - - process.exit(0); -})(); - -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); - - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); - - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; - - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); - - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); - - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - -``` - -#### Steps to Transfer Tokens - -The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: - -1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step - - ```typescript - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); - ``` - -2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying - - ```typescript - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); - - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; - ``` - -3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process - - ```typescript - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - ``` - - - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} - - ???- note "How Cross-Chain Transfers Work in the Background" - When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: - - - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount - - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains - - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network - - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer - - This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. - -4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain - - ```typescript - - ``` - -5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer - - ```typescript - console.log(`Completed Transfer: `, destTxids); - ``` - -??? code "Complete script" - ```typescript - import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); - - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); - - // Define the amount of tokens to transfer - const amt = '1'; - - // Set automatic transfer to false for manual transfer - const automatic = false; - - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); - - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); - - process.exit(0); -})(); - -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); - - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); - - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; - - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); - - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); - - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - - ``` - -### Run the Native Token Transfer - -Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: - -```bash -npx tsx src/scripts/native-transfer.ts -``` - -This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). - -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. - -## Resources - -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. - -## Conclusion - -You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. - -The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/tutorials/typescript-sdk/usdc-via-cctp/ ---- BEGIN CONTENT --- ---- -title: Transfer USDC via CCTP and Wormhole SDK -description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. ---- - -# Transfer USDC via CCTP and Wormhole SDK - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} - -## Introduction - -In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. - -Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. - -Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. - -In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. - -## Core Concepts - -When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: - - - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain - - - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you - -## Prerequisites - -Before you begin, ensure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples - - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees - -## Supported Chains - -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. - -## Project Setup - -In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. - -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project - - ```bash - mkdir cctp-circle - cd cctp-circle - npm init -y - ``` - -2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control - - ```bash - echo ".env" >> .gitignore - ``` - -3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries - - ```bash - npm install @wormhole-foundation/sdk dotenv - ``` - -4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project - - ```bash - touch .env - ``` - - Inside the `.env` file, add your private key - - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - ``` - - !!! note - Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. - -5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays - - 1. Create the helpers file - - ```bash - mkdir helpers - touch helpers/helpers.ts - ``` - - 2. Open the `helpers.ts` file and add the following code - - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { config } from 'dotenv'; -config(); - -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; -} - -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} - -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; - - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); - } - - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - - ``` - - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file - -6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains - - 1. Create the `manual-transfer.ts` file in the `src` directory - - ```bash - touch src/manual-transfer.ts - ``` - - 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files - - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; - ``` - - - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more - - **`solana`** - this adds support for Solana, a non-EVM chain - - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions - -## Manual Transfers - -In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. - -This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. - -### Set Up the Transfer Environment - -#### Configure Transfer Details - -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. - -1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed - - ```typescript - const wh = await wormhole('Testnet', [evm, solana]); - ``` - - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. - -2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them - - ```typescript - const rcvChain = wh.getChain('Sepolia'); - ``` - -3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains - - ```typescript - const destination = await getSigner(rcvChain); - ``` - -4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK - - ```typescript - - ``` - -5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself - - ```typescript - - ``` - -#### Initiate the Transfer - -To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. - -1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself - - ```typescript - amt, - source.address, - destination.address, - automatic - ); - ``` - -2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer - - ```typescript - console.log(`Started Transfer: `, srcTxids); - ``` - -#### Fetch the Circle Attestation (VAA) - -Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. - - -1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds - - ```typescript - - ``` - -2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout - - ```typescript - console.log(`Got Attestation: `, attestIds); - ``` - - The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain - -#### Complete the Transfer on the Destination Chain - -Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. - -Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain - -```typescript -console.log(`Completed Transfer: `, dstTxids); - - console.log('Circle Transfer status: ', xfer); - - process.exit(0); -``` - -The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed - -You can find the full code for the manual USDC transfer script below: - -???- code "`manual-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; - -(async function () { - const wh = await wormhole('Testnet', [evm, solana]); - - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); - - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000n; - - const automatic = false; - - // Create the Circle transfer object - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); - - console.log('Circle Transfer object created:', xfer); - - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); - - // Wait for Circle Attestation (VAA) - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(timeout); - console.log(`Got Attestation: `, attestIds); - - // Complete the transfer on the destination chain (Sepolia) - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, dstTxids); - - console.log('Circle Transfer status: ', xfer); - - process.exit(0); -})(); - ``` - -### Run Manual Transfer - -To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly - -```bash -npx ts-node src/manual-transfer.ts -``` - -This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). - -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. - -### Complete Partial Transfer - -In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. - -This feature is handy for recovering an incomplete transfer or when debugging. - -Here’s how you can complete a partial transfer using just the source chain and transaction hash: - -```typescript -wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); - - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); -``` - -You will need to provide the below requirements to complete the partial transfer: - -- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated -- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup - -This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. - -You can find the full code for the manual USDC transfer script below: - -??? code "`partial-transfer.ts`" - ```typescript - import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; - -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); - - // Grab chain Contexts -- these hold a reference to a cached rpc client - const rcvChain = wh.getChain('Sepolia'); - - // Get signer from local key - const destination = await getSigner(rcvChain); - - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) - - // Rebuild the transfer from the source txid - const xfer = await CircleTransfer.from( - wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); - - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); - - console.log('Circle Transfer status: ', xfer); - - process.exit(0); -})(); - ``` - -## Automatic Transfers - -The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. - -### Set Up the Transfer Environment - -#### Configure Transfer Details - -The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you - -```typescript - -``` - -#### Initiate the Transfer - -The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain - -```typescript -amt, - source.address, - destination.address, - automatic - ); -``` - -#### Log Transfer Details - -After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer - -```typescript -console.log(`Started Transfer: `, srcTxids); - - process.exit(0); -``` - -You can find the full code for the automatic USDC transfer script below: - -??? code "`automatic-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; - -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); - - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); - - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000_001n; - - const automatic = true; - - // Create the Circle transfer object (USDC-only) - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); - - console.log('Circle Transfer object created:', xfer); - - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); - - process.exit(0); -})(); - ``` - -### Run Automatic Transfer - -Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: - -```bash -npx ts-node src/automatic-transfer.ts -``` - -The automatic relayer will take care of fetching the attestation and completing the transfer for you. - -## Resources - -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. - -## Conclusion - -In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. - -By following these steps, you've learned how to: - -- Set up cross-chain transfers for native USDC between supported chains -- Handle both manual and automatic relaying of transactions -- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/ ---- BEGIN CONTENT --- ---- -title: Wormholescan API Tutorials -description: Explore step-by-step guides on using the Wormholescan API to fetch VAAs, validate signatures, check redemption status, and process cross-chain transactions. ---- - -# Wormholescan API - -Explore hands-on tutorials for using the Wormholescan API to retrieve blockchain data, track transactions, validate VAAs, check redemption status, and more. - -## Tutorials - -
- -- :octicons-repo-16:{ .lg .middle } **Replace Outdated Signatures in VAAs** - - --- - - Learn how to fetch VAAs, verify their validity, and replace outdated signatures using the Wormholescan API and Wormhole SDK. - - [:custom-arrow: Start tutorial](/docs/tutorials/wormholescan/replace-signatures/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **Wormholescan** - - --- - - Wormholescan is a blockchain explorer for tracking transactions, VAAs, and cross-chain activity. Its API provides programmatic access to transaction data, network analytics, and more. - - [:custom-arrow: Visit Wormholescan](https://wormholescan.io/){target=\_blank} - -
---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/tutorials/wormholescan/replace-signatures/ -======= -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ ->>>>>>> 50001c091b09baf8f8eecacccad16611effdfd7a ---- BEGIN CONTENT --- ---- -title: Replace Outdated Signatures in VAAs -description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. ---- - -# Replace Outdated Signatures in VAAs - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} - -## Introduction - -Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. - -However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. - -Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. - -In this tutorial, you'll build a script from scratch to: - -- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} -- Validate its signatures against the latest Guardian set -- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} -- Output a valid VAA ready for submission - -By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. - -## Prerequisites - -Before you begin, ensure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - -## Project Setup - -In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. - -1. **Create the project** - set up the directory and navigate into it - - ```bash - mkdir wormhole-scan-api-demo - cd wormhole-scan-api-demo - ``` - -2. **Initialize a Node.js project** - generate a `package.json` file - - ```bash - npm init -y - ``` - -3. **Set up TypeScript** - create a `tsconfig.json` file - - ```bash - touch tsconfig.json - ``` - - Then, add the following configuration: - - ```json title="tsconfig.json" - { - "compilerOptions": { - "target": "es2016", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - } -} - ``` - -4. **Install dependencies** - add the required packages - - ```bash - npm install @wormhole-foundation/sdk axios web3 tsx @types/node - ``` - - - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions - - `axios` - makes HTTP requests to the Wormholescan API - - `web3` - interacts with Ethereum transactions and contracts - - `tsx` - executes TypeScript files without compilation - - `@types/node` - provides Node.js type definitions - -5. **Create the project structure** - set up the required directories and files - - ```bash - mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts - mkdir -p src/helpers && touch src/helpers/vaaHelper.ts - mkdir -p src/scripts && touch scripts/replaceSignatures.ts - ``` - - - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures - - **`src/helpers/*`** - contains utility functions - - **`src/scripts/*`** - contains scripts for fetching and replacing signatures - -6. **Set variables** - define key constants in `src/config/constants.ts` - - ```bash title="src/config/constants.ts" - export const RPC = 'https://ethereum-rpc.publicnode.com'; + ```bash title="src/config/constants.ts" + export const RPC = 'https://ethereum-rpc.publicnode.com'; export const ETH_CORE = '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase(); @@ -14811,7 +13803,7 @@ Wormhole’s multichain messaging infrastructure connects the hub and spokes, en The diagram below illustrates this high-level architecture. -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/architecture-1.webp) ## Key Components @@ -14931,7 +13923,7 @@ MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensu This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. -![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/multigov-detailed.webp) +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ @@ -15564,19 +14556,19 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank} – optionally move assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets - **Coordinated Protocol Upgrades Across Chains** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains - **Progressive Decentralization for Multichain DAOs** - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – aggregate results and execute actions via the hub + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub ## Next Steps @@ -16640,8 +15632,13 @@ categories: NTT, Transfer This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. + +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. + ## Prerequisites Before deploying NTT on Solana, ensure you have the following: @@ -16767,14 +15764,13 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. - ### Generate an NTT Program Key Pair Create a unique key pair for the NTT program: - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +```bash +solana-keygen grind --starts-with ntt:1 --ignore-case +``` ### Set Mint Authority @@ -16893,6 +15889,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
--- END CONTENT --- @@ -17087,7 +16091,85 @@ Enter a new value to adjust limits and click **Update**. The changes will take e Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ --- BEGIN CONTENT --- -TODO +--- +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer +--- + +## Native Token Transfers Overview + +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. + +## Key Features + +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps + + +## Deployment Models + +NTT offers two operational modes for your existing tokens: + +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token + +## Supported Token Standards + +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. + +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. + +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. + +## Deployment Process + +Here's a breakdown of the key steps involved when deploying NTT: + +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed + +## Use Cases + +- **Cross-Chain Swaps and Liquidity Aggregation** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + +- **Borrowing and Lending Across Chains** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + +- **Gas Abstraction** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + +- **Cross-Chain Payment Widgets** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + +- **Cross-Chain Staking** + + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + +## Next Steps + +Follow these steps to get started with NTT: + +[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ @@ -17620,29 +16702,29 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/get-started/){target=\_blank} – transfer collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch live prices optimal trade execution - - [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution + - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades - **Multichain Prediction Markets** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetch market data and odds - - [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/build/queries/overview/){target=\_blank} – source data from chains - - [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks ## Next Steps @@ -17653,12 +16735,101 @@ Follow these steps to get started with Queries: Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ --- BEGIN CONTENT --- -TODO +--- +title: Queries Supported Methods +description: Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. +categories: Queries +--- + +# Supported Methods + +Wormhole Queries provides on-demand access to [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}-attested on-chain data through a simple REST endpoint. It offers a faster, gasless alternative to traditional transaction-based data retrieval, removing the need for gas fees and transaction finality delays. Requests are handled off-chain and processed by the Guardians, delivering verified data efficiently and cost-effectively. + +This page describes Wormhole Queries, their functionality, and available methods, aiming to assist new developers in utilizing the service. + +## Supported Query Types + +Wormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains. + +!!! note + For a more comprehensive technical description and further specifics on each query type, please consult the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md). + + +### eth_call + +The [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} query type allows you to perform read-only calls to a smart contract on a specific block, identified by its number or hash. Some of eth_call's configurations include: + +- **Batching** - group multiple calls, even to different contracts, into a single query targeting the same block, which is processed as one batch RPC call to simplify on-chain verification +- **Capacity** - batch up to 255 individual in a single eth_call query +- **Result data** - provides the specified block's number, hash, timestamp, and the output from the contract call + +### eth_call_by_timestamp + +The [`eth_call_by_timestamp`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#timestamp-and-block-id-hints-in-eth_call_by_timestamp){target=\_blank} query is similar to a standard `eth_call` but targets a specific timestamp instead of a block ID. This is useful for retrieving on-chain data based on a precise point in time, especially for correlating information across different chains. + +The query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block. + +### eth_call_with_finality + +The [`eth_call_with_finality`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#desired-finality-in-eth_call_with_finality){target=\_blank} query type functions like a standard `eth_call`, but with an added critical assurance: it will only return the query results once the specified block has reached a designated level of finality on its chain. + +You can specify one of two finality levels for your query: + +- **Finalized** - indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain +- **Safe** - refers to a block considered highly unlikely to be reorganized, offering a substantial degree of confidence, though the network's consensus may not fully finalize it + +!!! note + If the target blockchain does not natively support or recognize the safe finality tag, requesting safe finality will be treated as a request for finalized finality instead. + +### sol_account + +The [`sol_account`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana-queries){target=\_blank} query reads on-chain data for one or more specified accounts on the Solana blockchain. This functionality is similar to using Solana's native [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} RPC method, enabling you to retrieve information for multiple accounts simultaneously + +### sol_pda + +The [`sol_pda`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana_queries){target=\_blank} query reads data for one or more Solana [Program Derived Addresses](https://www.anchor-lang.com/docs/pdas){target=\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data. + +This is particularly useful for accessing multiple PDAs owned by a specific program or for verifying Solana PDA derivations on another blockchain, such as how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-networks/ --- BEGIN CONTENT --- -TODO +--- +title: Queries Supported Networks +description: Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. +categories: Queries +--- + +# Supported Networks + +This page provides a quick reference for chains supported by Wormhole Queries, including each chain's Wormhole chain ID and the level of support for key methods: [`eth_call`](/docs/products/queries/reference/supported-methods/#eth_call){target=\_blank}, [`eth_call_by_timestamp`](/docs/products/queries/reference/supported-methods/#eth_call_by_timestamp){target=\_blank}, and [`eth_call_with_finality`](/docs/products/queries/reference/supported-methods/#eth_call_with_finality){target=\_blank}. + +The **Expected History** column shows how much recent state data is typically available for querying, though this can vary depending on the chain and the configuration of each Guardian node. + +The support shown in the table reflects what has been confirmed through testing. However, query success ultimately depends on whether the underlying call can be executed on each Guardian’s RPC node. + +For example, many chains use a fork of [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which by default retains 128 blocks of state in memory (unless archive mode is enabled). On Ethereum mainnet, this covers around 25 minutes of history—but on faster chains like Optimism, it may span only about three minutes. While Guardian nodes are expected to have access to recent state, there are currently no guarantees on how far back historical data is available. + +## Mainnet + +| Chain | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History | +|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:| +| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | +| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | +| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | +| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | +| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | +| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | +| Karura | 11 | ✅ | ✅ | ✅ | archive | +| Acala | 12 | ✅ | ✅ | ✅ | archive | +| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | +| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks | +| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks | +| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | +| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | +| Base | 30 | ✅ | ✅ | ✅ | archive | + +ℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ @@ -17725,6 +16896,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | pacific-1 | | Seievm | 40 | | | SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | | Terra | 3 | columbus-5 | @@ -17781,6 +16953,7 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sei | 32 | atlantic-2 | | Seievm | 40 | | | SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | | Terra | 3 | bombay-12 | @@ -17840,6 +17013,7 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Polygon | 200 | | | finalized | ~ 66s | Details | | Scroll | 200 | | | finalized | ~ 16min | | | Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | | Terra | | | 0 | | ~ 6s | | @@ -17896,6 +17070,7 @@ categories: Reference | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | | Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | | Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | @@ -17997,6 +17172,7 @@ categories: Reference | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | | Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | @@ -18184,95 +17360,199 @@ Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ --- BEGIN CONTENT --- --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Environments - -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment +## Networks - +
-### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm +### Connect + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### NTT + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Move VM +### Token Bridge -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### NEAR VM +### CCTP -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-### Sui Move VM +### Settlement + +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
+ + +
-| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +### MultiGov + +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer |
- --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ @@ -18949,59 +18229,169 @@ To set up the Pyth Beacon (which is run using make `run-publisher`), you may nee sudo sysctl -w net.inet.udp.recvspace=2097152 ``` -### Running the Example Solver +### Running the Example Solver + +Using the same config for your publisher, run the example solver with the command below. + +```sh +CONFIG=path/to/config.json make run-solver +``` + +It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. + +This process reads the following environment variables: + +```sh +SOLANA_PRIVATE_KEY_1= +SOLANA_PRIVATE_KEY_2= +SOLANA_PRIVATE_KEY_3= +SOLANA_PRIVATE_KEY_4= +SOLANA_PRIVATE_KEY_5= +``` + +At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. + +The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. + +Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. + +An address lookup table is required to execute some transactions. Use the command below to create one. + +```sh +CONFIG=path/to/config.json make create-lut +``` + +`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. + +The example solver has the following toggles depending on which orders you want to fulfill: + +- `enableCctpOrderPipeline()` +- `enableLocalOrderPipeline()` +- `enablePlaceInitialOffer()` +- `enableImproveOffer()` + +See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. + +This example solver does NOT do the following: + +- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called +- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it +- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Settlement Overview +description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. +categories: Settlement, Transfer +--- + +# Settlement Overview + +Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. + +Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. + +It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. + +## Key Features + +- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. +- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. +- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. +- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. + +## How It Works + +At the core of Settlement are two components: + +- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. +- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. + +Settlement leverages the following three integrated protocols. + +### Mayan Swift + +Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. + +The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. + +1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. +2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. +3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. + +```mermaid +sequenceDiagram + participant User + participant Solver_ARB as Solver (Arbitrum) + participant Escrow + participant Wormhole + participant Solver_SOL as Solver (Solana) + participant Aggregator + + Note over User,Aggregator: User has ARB and wants WIF + + User->>Solver_ARB: Submit intent (ARB → WIF) + Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH + Escrow-->>Wormhole: Emits VAA + Wormhole-->>Solver_SOL: Delivers VAA + Solver_SOL->>Aggregator: Releases SOL and swaps to WIF + Aggregator->>Solver_SOL: Receives WIF + Solver_SOL->>User: Sends WIF + User-->>Wormhole: Emits final VAA + Wormhole-->>Escrow: Confirms receipt + Escrow->>Solver_ARB: Releases ETH to solver +``` + +### Liquidity Layer -Using the same config for your publisher, run the example solver with the command below. +The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. -```sh -CONFIG=path/to/config.json make run-solver -``` +### Mayan MCTP -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. -This process reads the following environment variables: +### One Integration, Three Ways -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` +Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. +By default, Settlement integrates all three: -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. +- The SDK automatically resolves the best route for each transfer. +- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. +- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. +Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. -An address lookup table is required to execute some transactions. Use the command below to create one. +To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. -```sh -CONFIG=path/to/config.json make create-lut -``` +## Use Cases -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. +- **Cross-Chain Perpetuals** -The example solver has the following toggles depending on which orders you want to fulfill: + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` +- **Bridging Intent Library** -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls -This example solver does NOT do the following: +- **Multichain Prediction Markets** -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state -Doc-Content: https://wormhole.com/docs/products/settlement/overview/ ---- BEGIN CONTENT --- -TODO +## Next Steps + +Start building with Settlement or dive deeper into specific components: + +- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. +- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/settlement/tutorials/.settlement-routes/ @@ -19165,7 +18555,284 @@ performSwap(); Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ --- BEGIN CONTENT --- -TODO +--- +title: Token Bridge Payload Structure +description: Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. +categories: Token-Bridge, Transfers +--- + +# Message and Payload Structure + +To enable secure and flexible cross-chain token transfers, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} defines a set of standardized payloads. These payloads are embedded in [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} and processed by bridge contracts on the source and destination chains. Each payload has a unique format and serves a specific role in the lifecycle of token bridging. + +This page outlines each payload type in detail. + +## Transfer + +The `Transfer` payload (ID = `1`) is the core mechanism for moving tokens across chains. It is emitted when a user locks or burns tokens on the source chain. On the destination chain, it instructs the bridge to either mint a wrapped token or release native tokens from custody. + +```text +PayloadID uint8 = 1 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +Fee uint256 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `1`, indicating a `Transfer` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals for consistency across all chains. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Left-zero-padded if shorter than 32 bytes. + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `Fee` ++"uint256"++ + + Amount of tokens that the user is willing to pay as relayer fee. Must be less than Amount. Optional and can be claimed by relayers who submit the VAA on the target chain. + + +To keep `Transfer` messages small, they don't carry all the token's metadata. However, this means that before a token can be transferred to a new chain for the first time, the metadata needs to be bridged, and the wrapped asset needs to be created. Metadata, in this case, includes the number of decimals, which is a core requirement for instantiating a token. + +## AssetMeta + +Before a token can be transferred to a new chain for the first time, its metadata must be attested using the `AssetMeta` payload (ID = `2`). This ensures proper decimal precision and display. + +```text +PayloadID uint8 = 2 +TokenAddress [32]uint8 +TokenChain uint16 +Decimals uint8 +Symbol [32]uint8 +Name [32]uint8 +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `2`, indicating a `AssetMeta` operation. + + --- + + `TokenAddress` ++"[32]uint8"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `Decimals` ++"uint8"++ + + Number of decimals the token uses on its native chain (not truncated to 8). + + --- + + `Symbol` ++"[32]uint8"++ + + Symbol of the token, UTF-8 encoded and padded to 32 bytes. + + --- + + `Name` ++"[32]uint8"++ + + Name of the token, UTF-8 encoded and padded to 32 bytes. + +## TransferWithPayload + +The `TransferWithPayload` payload (ID = `3`) extends the standard token transfer by allowing developers to include arbitrary data. This enables interactions with destination chain smart contracts, such as triggering swaps or staking. + +```text +PayloadID uint8 = 3 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +FromAddress bytes32 +Payload bytes +``` + +??? interface "Parameters" + + `PayloadID` ++"uint8"++ + + Value must be `3`, indicating a `TransferWithPayload` operation. + + --- + + `Amount` ++"uint256"++ + + Amount being transferred, truncated to 8 decimals. + + --- + + `TokenAddress` ++"bytes32"++ + + Address of the token. Left-zero-padded if shorter than 32 bytes. + + --- + + `TokenChain` ++"uint16"++ + + Chain ID of the token. + + --- + + `To` ++"bytes32"++ + + Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes + + --- + + `ToChain` ++"uint16"++ + + Chain ID of the recipient. + + --- + + `FromAddress` ++"bytes32"++ + + Address of the sender on the source chain. + + --- + + `Payload` ++"bytes"++ + + Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic. + + +Unlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly. + +## RegisterChain + +The `RegisterChain` governance payload (Action ID = `1`) registers a Token Bridge emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers. + +```text +Module [32]byte +Action uint8 = 1 +ChainId uint16 + +EmitterChainID uint16 +EmitterAddress [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier. Left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `1`, indicating a `RegisterChain` operation. + + --- + + `ChainID` ++"uint16"++ + + The chain where this governance action should be applied. `0` is a valid value for all chains + + --- + + `EmitterChainID` ++"uint16"++ + + Chain ID of the registered emitter. + + --- + + `EmitterAddress` ++"[32]uint8"++ + + Address of the registered emitter, left-zero-padded if shorter than 32 bytes. + +This payload can only be emitted by the Wormhole governance contract, ensuring that each chain accepts messages only from one verified bridge emitter per remote chain. + +## UpgradeContract + +The `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the Token Bridge contract on a specific chain. + +```text +Module [32]byte +Action uint8 = 2 +ChainId uint16 + +NewContract [32]uint8 +``` + +??? interface "Parameters" + + `Module` ++"[32]byte"++ + + Module identifier, left-padded with `TokenBridge` for Token Bridge. + + --- + + `Action` ++"uint8"++ + + Value must be `2`, indicating an `UpgradeContract` operation. + + --- + + `ChainID` ++"uint16"++ + + The target chain where the governance action should be applied. + + --- + + `NewContract` ++"[32]uint8"++ + + Address of the new Token Bridge contract, left-zero-padded to 32 bytes. + +This message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security. + +## Summary of Payload Structure + +| Payload Type | ID | Purpose | Who Emits It | +|-----------------------|---------------|------------------------------------------------------------------------|------------------------| +| `Transfer` | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination | Token Bridge contract | +| `AssetMeta` | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer | Token Bridge contract | +| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution | Token Bridge contract | +| `RegisterChain` | Action `1` | Registers a verified Token Bridge emitter for a foreign chain | Wormhole governance | +| `UpgradeContract` | Action `2` | Upgrades the Token Bridge contract on a specific chain | Wormhole governance | --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ @@ -19180,7 +18847,7 @@ categories: Token-Bridge, Transfer ## Introduction -The [Wormhole Token Bridge](/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. +The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. @@ -19192,7 +18859,7 @@ Cross-chain token transfers using the Token Bridge follow these steps: The transfer begins when a user calls the Token Bridge contract on the source chain: - **Wrapped tokens**: The token is burned. - - **Native tokens**: The token is locked in the contract. + - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. 2. **Transfer Message Publication** The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. @@ -19212,18 +18879,48 @@ Cross-chain token transfers using the Token Bridge follow these steps: After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: - **Wrapped tokens**: A wrapped representation of the original token is minted. - - **Native tokens**: The original token is released to the recipient. + - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. + +Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. ```mermaid sequenceDiagram - participant User - participant TokenBridgeSrc as Token Bridge
(Source Chain) - participant CoreSrc as Core Contract
(Source Chain) + participant Alice as Alice + participant TokenBridgeEth as Token Bridge Ethereum
(Source Chain) + participant CoreEth as Core Contract Ethereum
(Source Chain) + participant Guardians + participant TokenBridgeSol as Token Bridge Solana
(Destination Chain) + participant CoreSol as Core Contract Solana
(Destination Chain) + + Alice->>TokenBridgeEth: Initiate ETH transfer
(lock ETH) + TokenBridgeEth->>CoreEth: Publish transfer message + CoreEth-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA + + alt Automatic VAA submission + Guardians->>TokenBridgeSol: Relayer submits VAA + else Manual VAA submission + Alice->>Guardians: Retrieve VAA + Alice->>TokenBridgeSol: Submit VAA + end + + TokenBridgeSol->>CoreSol: Verify VAA + CoreSol-->>TokenBridgeSol: VAA verified + TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +``` + +Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. + +```mermaid +sequenceDiagram + participant User as Alice + participant TokenBridgeSrc as Token Bridge Solana
(Source Chain) + participant CoreSrc as Core Contract Solana
(Source Chain) participant Guardians - participant TokenBridgeDst as Token Bridge
(Destination Chain) - participant CoreDst as Core Contract
(Destination Chain) + participant TokenBridgeDst as Token Bridge Ethereum
(Destination Chain) + participant CoreDst as Core Contract Ethereum
(Destination Chain) - User->>TokenBridgeSrc: Initiate transfer
(burn/lock token) + User->>TokenBridgeSrc: Initiate transfer
(burn wrapped ETH) TokenBridgeSrc->>CoreSrc: Publish message CoreSrc-->>Guardians: Emit message event Guardians->>Guardians: Sign and publish VAA @@ -19237,9 +18934,10 @@ sequenceDiagram TokenBridgeDst->>CoreDst: Verify VAA CoreDst-->>TokenBridgeDst: VAA verified - TokenBridgeDst-->>User: Complete transfer (mint/release token) + TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) ``` + ## Automatic vs. Manual Transfers The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: @@ -19660,24 +19358,102 @@ import { getSigner, getTokenDecimals } from './helper';
-To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a manual multichain token transfer, explore these guides to continue building: + + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/transfer-wrapped-assets/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer +--- + +# Token Bridge Overview + +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. + +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. + +## Key Features + +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: + +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity + +## How It Works + +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: + +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain + +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. + +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana + + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message -## Next Steps + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) -Now that you've completed a manual multichain token transfer, explore these guides to continue building: + Solana->>Alice: Deliver wrapped ETH on Solana +``` - - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) - - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains ---- END CONTENT --- +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. -Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/transfer-wrapped-assets/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +## Use Cases -Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ ---- BEGIN CONTENT --- -TODO +Here are key use cases that highlight the power and versatility of the Token Bridge. + +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + +- **Tokenized Gaming Rewards** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + +- **Multichain DeFi Arbitrage** + + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + +## Next Steps + +If you are looking for more guided practice, take a look at: + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ @@ -19813,7 +19589,7 @@ Before you begin, ensure you have the following: ## Supported Chains -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. ## Project Setup @@ -21826,75 +21602,7 @@ More demos are available in the [demos page](/docs/build/start-building/demos/){ Wormhole supports a growing number of blockchains. - - -
- -### EVM - -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :x: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### SVM - -| Solana | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Pythnet | SVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### AVM - -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### CosmWasm - -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neutron | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Move VM - -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### NEAR VM - -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | - -### Sui Move VM - -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
- +text/supported-networks.md --- END CONTENT --- Doc-Content: https://wormhole.com/docs/protocol/security/ @@ -21976,41 +21684,429 @@ Wormhole builds in the open and is always open source. - **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** - **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** -## Audits +## Audits + +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} + +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + +## Bug Bounties + +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. + +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. + +## Learn More + +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with the Solidity SDK +description: Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. +categories: Basics, Solidity-SDK +--- + +# Get Started with the Solidity SDK + +The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} provides Solidity interfaces, prebuilt contracts, and testing tools to help Solidity developers build on-chain Wormhole integrations via smart contracts. You can use the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} for off-chain integrations without writing Solidity. + +## Install the SDK + +Use Foundry's [`forge`](https://book.getfoundry.sh/forge/){target=\_blank} to install the SDK using the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +## Key Components + +The following key components and features work together to make your on-chain Wormhole integration easier to build. + +??? interface "Base contracts" + + Leverage base contracts to send and receive messages and tokens. + + - [**`Base.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Base.sol){target=\_blank}: Uses Wormhole interfaces to authorize and verify a registered sender. + - [**`TokenBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/TokenBase.sol){target=\_blank}: Uses `TokenReceiver` and `TokenSender` contracts to define functions for transferring tokens. + - [**`CCTPBase.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPBase.sol){target=\_blank}: Uses `CCTPSender` and `CCTPReceiver` contracts to define functions for transferring USDC. + +??? interface "Interfaces" + + Use interfaces to ensure consistent interactions with the protocol regardless of the supported chain you use. + + - [**`ITokenBridge.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/ITokenBridge.sol){target=\_blank}: Defines key structs and functions for token attestation, wrapping and transferring tokens, monitoring transaction progress. + - [**CCTP Interfaces**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/CCTPInterfaces){target=\_blank}: A set of interfaces for USDC transfers via CCTP for sending, relaying, and receiving messages and tokens. + - [**`IWormholeReceiver.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeReceiver.sol){target=\_blank}: Defines the `receiveWormholeMessages` function. + - [**`IWormholeRelayer.sol`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/interfaces/IWormholeRelayer.sol){target=\_blank}: Defines key structs and functions to identify, send, and deliver messages and follow the progress of transactions. + +??? interface "Constants" + + Auto-generated Solidity constants help avoid manual entry errors and ensure consistent delivery. + + - [**Wormhole Chain ID's**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/Chains.sol){target=\_blank}: Generated list of Wormhole Chain ID's for supported chains. + - [**Circle CCTP Domain IDs**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/b9e129e65d34827d92fceeed8c87d3ecdfc801d0/src/CCTPAndTokenBase.sol){target=\_blank}: Generated list of defined CCTP domain ID's to ensure USDC transfers use the correct domain for a given chain. + - [**`chainConsts.ts`**](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/75ddcec06ffe9d62603d023357caa576c5ea101c/gen/chainConsts.ts){target=\_blank}: Returns values to identify properties and contract addresses for each supported chain. + +## Example Usage + +The following demo illustrates the use of Wormhole Solidity SDK-based smart contracts to send testnet USDC between supported chains. + +### Prerequisites +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} installed +- Testnet tokens for two supported chains. This example uses [testnet AVAX for Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [testnet CELO for Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} and can be adapted to any supported chains +- [USDC testnet tokens](https://faucet.circle.com/){target=\_blank} on your source chain for cross-chain transfer + +### Set Up a Project + +Follow these steps to prepare your development environment: + +1. Create a directory for your project, navigate into it, and install the Wormhole Solidity SDK: + + ```bash + mkdir solidity-token-transfer + cd solidity-token-transfer + forge install wormhole-foundation/wormhole-solidity-sdk + ``` + +2. Install dependencies for use with your transfer script, including the Wormhole TypeScript SDK, and initiate a new Node.js project: + + ```bash + npm init -y && npm install @wormhole-foundation/sdk ethers -D tsx typescript + ``` + +### Create and Deploy Contracts + +This project uses sender and receiver contracts to access the `WormholeRelayer` interface's [`TokenSender`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L24){target=\_blank} and [`TokenReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/baa085006586a43c42858d355e3ffb743b80d7a4/src/WormholeRelayer/TokenBase.sol#L147){target=\_blank} base classes to simplify sending tokens across chains. + +Follow these steps to create and deploy your sender and receiver Solidity contracts: + +1. Use the following example code to create `CrossChainSender.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenSender contract inherited from TokenBase +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Calculate the estimated cost for multichain token transfer using + // the wormholeRelayer to get the delivery cost and add the message fee + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + + cost = deliveryCost + wormhole.messageFee(); + } + + // Send tokens and payload to the recipient on the target chain + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + // Calculate the estimated cost for the multichain deposit + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); + // Transfer the tokens from the sender to this contract + IERC20(token).transferFrom(msg.sender, address(this), amount); + // Encode the recipient address into the payload + bytes memory payload = abi.encode(recipient); + // Initiate the multichain transfer using the wormholeRelayer + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} + ``` + + This contract extends `TokenSender`, gaining access to its functionality. It initializes the contract with the required addresses, calculates estimated transfer costs, defines transfer parameters, and initiates the transfer using the `sendTokenWithPayloadToEvm` function from `WormholeRelayer`. + +2. Use the following example code to create `CrossChainReceiver.sol`: + + ```solidity title="CrossChainSender.sol" + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + +// Extend the TokenReceiver contract inherited from TokenBase +contract CrossChainReceiver is TokenReceiver { + // Initialize the contract with the Wormhole relayer, Token Bridge, + // and Wormhole Core Contract addresses + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + // Receive the multichain payload and tokens + // Verify the transfer is from a registered sender + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + // Ensure the payload is not empty and only has one token transfer + require(receivedTokens.length == 1, "Expected 1 token transfer"); + + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); + + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` + + This contract extends `TokenReceiver`, gaining access to its functionality. It initializes the contract with the required addresses, receives the payload and tokens, verifies the transfer is from a registered sender, decodes the recipient address, and transfers the tokens to the recipient. + +3. Deploy the contracts using your preferred deployment method. Make sure you deploy `CrossChainSender.sol` to your desired source chain and `CrossChainReceiver.sol` to the target chain. Save the deployed contract addresses for each contract. You will need them for your transfer script. + +## Use Contracts to Transfer USDC + +1. Once your contracts are deployed, create a `transfer.ts` file to handle the multichain transfer logic: + + ```bash + touch script/transfer.ts + ``` + +2. Set up secure access to your wallets. This guide assumes you are loading your private key(s) from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +3. Open `transfer.ts` and add the following code: + + ```typescript title="transfer.ts" + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import readlineSync from 'readline-sync'; +import { fileURLToPath } from 'url'; +import { wormhole, chainToChainId } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; + +// Replace with your contract address and chain names +const AVALANCHE_SENDER_ADDRESS = 'INSERT_AVALANCHE_SENDER_CONTRACT_ADDRESS'; +const CELO_RECEIVER_ADDRESS = 'INSERT_CELO_RECEIVER_ADDRESS'; +const AVALANCHE_CHAIN_NAME = 'Avalanche'; +const CELO_CHAIN_NAME = 'Celo'; + +// Fetch the contract ABI from the local filesystem +// This example uses the `out` directory from a Foundry deployment +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const SENDER_ABI_PATH = path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' +); + +(async function () { + try { + console.log('Initializing Wormhole SDK...'); + const wh = await wormhole('Testnet', [evm]); + const sendChain = wh.getChain(AVALANCHE_CHAIN_NAME); + const rcvChain = wh.getChain(CELO_CHAIN_NAME); + + // The EVM_PRIVATE_KEY value must be loaded securely beforehand, + // for example via a keystore, secrets manager, or environment variables + // (not recommended) + const EVM_PRIVATE_KEY = EVM_PRIVATE_KEY!; + if (!EVM_PRIVATE_KEY) { + console.error('EVM_PRIVATE_KEY is not set in your .env file.'); + process.exit(1); + } + + // Get the RPC URL or Provider from the SDK + const sourceRpcOrProvider = await sendChain.getRpc(); + let sourceProvider: ethers.JsonRpcProvider; + if ( + sourceRpcOrProvider && + typeof (sourceRpcOrProvider as any).getBlockNumber === 'function' + ) { + sourceProvider = sourceRpcOrProvider as ethers.JsonRpcProvider; + } else if (typeof sourceRpcOrProvider === 'string') { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider); + } else if ( + Array.isArray(sourceRpcOrProvider) && + typeof sourceRpcOrProvider[0] === 'string' + ) { + sourceProvider = new ethers.JsonRpcProvider(sourceRpcOrProvider[0]); + } else { + console.error( + 'Could not get a valid RPC URL or Provider from SDK:', + sourceRpcOrProvider + ); + process.exit(1); + } + + // Create the wallet using the provider and private key + const sourceWallet = new ethers.Wallet(EVM_PRIVATE_KEY, sourceProvider); + + // Load the sender contract ABI + if (!fs.existsSync(SENDER_ABI_PATH)) { + console.error(`ABI file not found at ${SENDER_ABI_PATH}`); + process.exit(1); + } + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync(SENDER_ABI_PATH, 'utf8') + ); + const senderAbi = CrossChainSenderArtifact.abi; + + // Create new sender contract instance + const senderContract = new ethers.Contract( + AVALANCHE_SENDER_ADDRESS, + senderAbi, + sourceWallet + ); + + // Get user input for token transfer parameters + const tokenAddress = readlineSync.question( + 'Enter the (ERC20) token contract address on Avalanche: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on Celo: ' + ); + const amountStr = readlineSync.question( + 'Enter the amount of tokens to transfer: ' + ); -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: + // Approve sending tokens from the source wallet to the sender contract + const tokenContract = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + 'function allowance(address owner, address spender) view returns (uint256)', + ], + sourceWallet + ); -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} + // Convert the amount to the correct units based on token decimals + const decimals = Number(await tokenContract.decimals()); + const amountToTransfer = ethers.parseUnits(amountStr, decimals); + + // Get a transfer cost quote + const targetChainId = chainToChainId(rcvChain.chain); + const cost = await senderContract.quoteCrossChainDeposit(targetChainId); + // Approve the sender contract to spend the tokens + const approveTx = await tokenContract.approve( + AVALANCHE_SENDER_ADDRESS, + amountToTransfer + ); + await approveTx.wait(); -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. + // Initiate the transfer + console.log( + `Initiating cross-chain transfer to ${CELO_RECEIVER_ADDRESS} on ${rcvChain.chain}...` + ); + const transferTx = await senderContract.sendCrossChainDeposit( + targetChainId, + CELO_RECEIVER_ADDRESS, + recipientAddress, + amountToTransfer, + tokenAddress, + { value: cost } + ); + console.log(`Transfer transaction sent: ${transferTx.hash}`); + await transferTx.wait(); + console.log(`✅ Transfer initiated successfully!`); + } catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } -## Bug Bounties + process.exit(0); +})(); + ``` -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. + This script defines the sender and receiver contract addresses, fetches the necessary ABI information, creates a connected signer, converts decimals, calculates the estimated transfer cost, and initiates the token transfer. -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +3. Run the script using the following command: -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. + ```bash + npx tsx script/transfer.ts + ``` -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +4. Follow the prompts in the terminal. This example uses Avalanche Fuji as the source chain, Celo Testnet as the target, [Avalanche Fuji testnet USDC](https://developers.circle.com/stablecoins/usdc-on-test-networks){target=\_blank}, and a developer wallet as the recipient address. You will see terminal output similar to the following: -## Learn More +
+npx tsx script/transfer.ts +Initializing Wormhole SDK... +Enter the (ERC20) token contract address on Avalanche: 0x5425890298aed601595a70ab815c96711a31bc65 +Enter the recipient address on Celo: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Initiating cross-chain transfer to 0xff97a7141833fbe829249d4e8952A8e73a4a2fbd on Celo... +Transfer transaction sent: 0x2d819aadf88309eb19f59a510aba1f2892b54487f9e287feadd150181a28f771 +✅ Transfer initiated successfully! + +
-The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. ---- END CONTENT --- +Congratulations! You've successfully created and deployed Wormhole Solidity SDK-based smart contracts and used them to send testnet USDC across blockchains. Consider the following options to build upon what you've accomplished. -Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ ---- BEGIN CONTENT --- -TODO +## Next Steps + +- [**Get Started with Messaging**](/docs/products/messaging/get-started/): Send a message across blockchains using the Wormhole TypeScript SDK to eliminate smart contract development and auditing overhead. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/sdk-reference/ @@ -22088,18 +22184,7 @@ Please refer to the complete `WormholeRelayerSDK.sol` file below for further det ???- code "`WormholeRelayerSDK.sol`" ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/constants/Chains.sol"; -import "wormhole-sdk/Utils.sol"; - -import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; -import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; -import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; -import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; + code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol ``` ### Base Contract Overview @@ -22109,87 +22194,20 @@ The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/bl - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions ```solidity - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:22:28 ``` - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources ```solidity - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:45:54 ``` These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. ???- code "`Base.sol`" ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; - -import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; -import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/Utils.sol"; - -abstract contract Base { - IWormholeRelayer public immutable wormholeRelayer; - IWormhole public immutable wormhole; - - address registrationOwner; - mapping(uint16 => bytes32) registeredSenders; - - constructor(address _wormholeRelayer, address _wormhole) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - wormhole = IWormhole(_wormhole); - registrationOwner = msg.sender; - } - - modifier onlyWormholeRelayer() { - require( - msg.sender == address(wormholeRelayer), - "Msg.sender is not Wormhole Relayer" - ); - _; - } - - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } - - /** - * Sets the registered address for 'sourceChain' to 'sourceAddress' - * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid - * - * Assumes only one sender per chain is valid - * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) - */ - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -} + code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol ``` ### Interface for Cross-Chain Messages @@ -22224,32 +22242,7 @@ This section covers cross-chain messaging and token transfers and shows how to u To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; - -contract CrossChainSender is Base { - constructor( - address _wormholeRelayer, - address _wormhole - ) Base(_wormholeRelayer, _wormhole) {} - - function sendMessage( - bytes memory message, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Register sender and send message through WormholeRelayer - setRegisteredSender(targetChain, msg.sender); - onlyWormholeRelayer().sendPayloadToEvm( - targetChain, - address(targetAddress), - message, - 0, - 500_000 - ); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol ``` This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. @@ -22259,26 +22252,7 @@ This contract extends `Base.sol` and allows sending cross-chain messages securel The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenSender is TokenSender { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenSender(_wormholeRelayer, _wormhole) {} - - function sendToken( - address token, - uint256 amount, - uint16 targetChain, - bytes32 targetAddress - ) external payable { - // Send tokens across chains - transferTokenToTarget(token, amount, targetChain, targetAddress); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol ``` In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. @@ -22288,28 +22262,7 @@ In this example, `TokenSender` initiates a token transfer to another chain. The To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. ```solidity -pragma solidity ^0.8.19; - -import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; - -contract CrossChainTokenReceiver is TokenReceiver { - constructor( - address _wormholeRelayer, - address _wormhole - ) TokenReceiver(_wormholeRelayer, _wormhole) {} - - // Function to handle received tokens from another chain - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable override { - // Process the received tokens here - receiveTokens(payload); - } -} +code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol ``` In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. @@ -22329,7 +22282,243 @@ For a detailed example, check out the below repositories: Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/get-started/ --- BEGIN CONTENT --- +--- +title: Get Started with the TypeScript SDK +description: Follow this guide to install the Wormhole TypeScript SDK, initialize a Wormhole instance, and add the platforms your integration supports. +categories: Typescript-SDK +--- + +# Get Started with the TypeScript SDK + +## Introduction + +The Wormhole TypeScript SDK provides a unified, type-safe interface for building cross-chain applications. It is a foundational toolkit that supports interaction with core Wormhole protocols, including Native Token Transfers, Token Bridge, CCTP, and Settlement, giving developers a consistent API across multiple chains. + +This guide helps you install the SDK, initialize a `Wormhole` instance to support your desired network and blockchain platforms, and return chain-specific information to verify successful initialization. + +If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: + + ```bash + npm install --save-dev tsx typescript @types/node + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +## Install the SDK + +To install the Wormhole TypeScript SDK, use the following command: + +```bash +npm install @wormhole-foundation/sdk +``` + +This package combines all the individual packages to make setup easier. + +You can choose to install a specific set of packages as needed. For example, to install EVM-specific utilities, you can run: + +```bash +npm install @wormhole-foundation/sdk-evm +``` + +??? example "Complete list of individually published packages" + + Platform-Specific Packages + + - `@wormhole-foundation/sdk-evm` + - `@wormhole-foundation/sdk-solana` + - `@wormhole-foundation/sdk-algorand` + - `@wormhole-foundation/sdk-aptos` + - `@wormhole-foundation/sdk-cosmwasm` + - `@wormhole-foundation/sdk-sui` + + --- + + Protocol-Specific Packages + + - Core Protocol + - `@wormhole-foundation/sdk-evm-core` + - `@wormhole-foundation/sdk-solana-core` + - `@wormhole-foundation/sdk-algorand-core` + - `@wormhole-foundation/sdk-aptos-core` + - `@wormhole-foundation/sdk-cosmwasm-core` + - `@wormhole-foundation/sdk-sui-core` + + - Token Bridge + - `@wormhole-foundation/sdk-evm-tokenbridge` + - `@wormhole-foundation/sdk-solana-tokenbridge` + - `@wormhole-foundation/sdk-algorand-tokenbridge` + - `@wormhole-foundation/sdk-aptos-tokenbridge` + - `@wormhole-foundation/sdk-cosmwasm-tokenbridge` + - `@wormhole-foundation/sdk-sui-tokenbridge` + + - CCTP + - `@wormhole-foundation/sdk-evm-cctp` + - `@wormhole-foundation/sdk-solana-cctp` + - `@wormhole-foundation/sdk-aptos-cctp` + - `@wormhole-foundation/sdk-sui-cctp` + + - Other Protocols + - `@wormhole-foundation/sdk-evm-portico` + - `@wormhole-foundation/sdk-evm-tbtc` + - `@wormhole-foundation/sdk-solana-tbtc` + + --- + + Utility Packages + + - `@wormhole-foundation/sdk-base` + - `@wormhole-foundation/sdk-definitions` + - `@wormhole-foundation/sdk-connect` + + +## Initialize the SDK + +You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. + +1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + +2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; +// Import specific platform modules for the chains you intend to use +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + // Determine the network: "Mainnet", "Testnet", or "Devnet" + const network = 'Testnet'; + + // Initialize the SDK with the chosen network and platform contexts + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); +} + +main().catch((e) => { + console.error('Error initializing Wormhole SDK', e); + process.exit(1); +}); + ``` + +## Fetch Chain Information + +Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. + +1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + const network = 'Testnet'; + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); + + // Example: Get a chain ID and RPC for Solana + const solanaDevnetChain = wh.getChain('Solana'); + console.log( + `Chain ID for Solana Testnet: ${solanaDevnetChain.config.chainId}` + ); + console.log(`RPC for Solana Testnet: ${solanaDevnetChain.config.rpc}`); + + // Example: Get a chain ID for Sepolia (EVM Testnet) + const sepoliaChain = wh.getChain('Sepolia'); + console.log(`Chain ID for Sepolia: ${sepoliaChain.config.chainId}`); + console.log(`RPC for Sepolia: ${sepoliaChain.config.rpc}`); +} + +main().catch((e) => { + console.error( + 'Error initializing Wormhole SDK or fetching chain information:', + e + ); + process.exit(1); +}); + ``` + +2. Run the script with the following command, replacing `INSERT_FILE_NAME` with your file name: + + ```bash + npx tsx INSERT_FILE_NAME + ``` + + You will see terminal output similar to the following: + +
+npx tsx src/main.ts +Initializing Wormhole SDK... +Wormhole SDK Initialized! +Chain ID for Solana Testnet: 1 +RPC for Solana Testnet: https://api.devnet.solana.com +Chain ID for Sepolia: 10002 +RPC for Sepolia: https://ethereum-sepolia.publicnode.com + +
+ +Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and initialized a `Wormhole` instance. Consider the following options to build on what you've accomplished. + +## Next Steps +- [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) +- [Send a multichain message](TODO: get started messaging) +- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) +- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ diff --git a/llms.txt b/llms.txt index c2878ccaa..0b8bd3dc9 100644 --- a/llms.txt +++ b/llms.txt @@ -30,9 +30,9 @@ - [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. - [AI Resources](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md): Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): No description available. +- [Get Started with CCTP](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md): No description available. +- [CCTP Bridge with Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md): Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. - [Complete USDC Transfer Flow](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. - [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. - [Configure Your Connect Widget v0](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/configuration-v0.md): Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. @@ -41,10 +41,10 @@ - [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [Get Started with Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md): Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. - [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md): No description available. +- [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md): With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. - [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. - [Integrate Connect into a React DApp Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md): Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -- [Get Started with Messaging](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md): Follow this guide to deploy Wormhole Solidity SDK-based message sender and receiver smart contracts and use them to send messages across chains. +- [Get Started with Messaging](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md): Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. - [Get Started with Core Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/core-contracts.md): This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts - [Wormhole-Deployed Relayers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/guides/wormhole-relayers.md): Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - [Messaging Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/overview.md): With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. @@ -69,7 +69,7 @@ - [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md): No description available. +- [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md): With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. - [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. - [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. - [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. @@ -82,12 +82,12 @@ - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md): No description available. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md): No description available. - [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md): Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md): No description available. +- [Queries Supported Methods](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md): Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. +- [Queries Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md): Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. - [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. - [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. - [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. -- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +- [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. - [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. - [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. - [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. @@ -95,14 +95,14 @@ - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md): No description available. - [Wormhole Settlement Liquidity Layer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md): Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. - [Wormhole Settlement Solver](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md): Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md): No description available. +- [Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md): Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. - [Wormhole Settlements](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/tutorials/.settlement-routes.md): Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md): No description available. +- [Token Bridge Payload Structure](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md): Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. - [Flow of a Token Bridge Transfer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. - [Token Bridge FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md): Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. - [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md): No description available. +- [Token Bridge Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md): With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. - [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. - [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains - [Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/architecture.md): Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. @@ -115,9 +115,9 @@ - [VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md): Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. - [Introduction to Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md): Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. - [Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md): Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md): No description available. +- [Get Started with the Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md): Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. - [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md): No description available. +- [Get Started with the TypeScript SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md): Follow this guide to install the Wormhole TypeScript SDK, initialize a Wormhole instance, and add the platforms your integration supports. - [Building Protocols and Payloads](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md): Learn how to build, register, and integrate protocols and payloads in the Wormhole TypeScript SDK with type-safe layouts. - [Data Layouts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md): Learn how to efficiently define, serialize, and deserialize data structures using Wormhole SDK's layout system for cross-chain communication. - [VAAs and Protocols](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/vaas-protocols.md): Understand how VAAs enable cross-chain messaging and how to handle them using Wormhole's TypeScript and Solidity SDKs. diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index e9b056b41..69c1371b5 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -142,14 +142,13 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an !!! note Testnet deployment settings work for both Solana Testnet and Devnet networks. - ### Generate an NTT Program Key Pair Create a unique key pair for the NTT program: - ```bash - solana-keygen grind --starts-with ntt:1 --ignore-case - ``` +```bash +solana-keygen grind --starts-with ntt:1 --ignore-case +``` ### Set Mint Authority @@ -268,4 +267,12 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} +
diff --git a/products/reference/supported-networks.md b/products/reference/supported-networks.md index 8c53ecd48..2d8a582e3 100644 --- a/products/reference/supported-networks.md +++ b/products/reference/supported-networks.md @@ -1,23 +1,18 @@ --- title: Supported Networks -description: Learn about the compatible environments and individual networks that Wormhole supports. Readers can click on each of the blockchain logos for more information. +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. categories: Reference --- # Supported Networks -Wormhole supports several different blockchains and environments. Since many of the concepts for using Wormhole within a given blockchain environment are the same, this section is organized by environment, and individual chains are detailed within the environment page. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Supported Environments +## Networks -- [EVM (Ethereum and compatible chains)](#evm) -- [SVM (Solana and compatible chains)](#svm) -- [CosmWasm (Cosmos ecosystem chains)](#cosmwasm) -- [AVM (Algorand)](#avm) -- [NEAR VM (NEAR)](#near-vm) -- [Move VM (Aptos)](#move-vm) -- [Sui Move VM (Sui)](#sui-move-vm) - -## Supported Blockchains by Environment - ---8<-- 'text/supported-networks.md' +--8<-- 'text/build/start-building/supported-networks/connect.md' +--8<-- 'text/build/start-building/supported-networks/ntt.md' +--8<-- 'text/build/start-building/supported-networks/token-bridge.md' +--8<-- 'text/build/start-building/supported-networks/cctp.md' +--8<-- 'text/build/start-building/supported-networks/settlement.md' +--8<-- 'text/build/start-building/supported-networks/multigov.md' \ No newline at end of file diff --git a/products/token-bridge/tutorials/transfer-workflow.md b/products/token-bridge/tutorials/transfer-workflow.md index 878f2e1e5..020c1bd6b 100644 --- a/products/token-bridge/tutorials/transfer-workflow.md +++ b/products/token-bridge/tutorials/transfer-workflow.md @@ -33,7 +33,7 @@ Before you begin, ensure you have the following: ## Supported Chains -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=\_blank}, which covers both testnet and mainnet environments. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. ## Project Setup diff --git a/variables.yml b/variables.yml index a06eeca9c..6a767184b 100644 --- a/variables.yml +++ b/variables.yml @@ -4,7 +4,7 @@ ntt: repositories: wormhole_sdk: repository_url: https://github.com/wormhole-foundation/wormhole-sdk-ts - version: 1.17.0 + version: 1.20.0 wormhole: repository_url: https://github.com/wormhole-foundation/wormhole version: 2.33.0 From 356987c05da3f3d55a7ee469d4e1472d2414b0e8 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 09:43:40 -0400 Subject: [PATCH 36/55] Clean up old pages on the staging branch (#437) * update sdk to the latest version (#374) * Add gitignore step (#372) * add instructions for including .gitignore when starting fresh projects * update llms --------- Co-authored-by: Martin Hofmann * update sdk to latest version (#386) * multiple ntt cli feedback adjustments (#389) * multiple ntt cli feedback adjustments * generate llms * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * re-generate llms files --------- Co-authored-by: Erin Shaben * Martinh/faq link in ntt (#384) * add faws link to solana deployment page * llms check * update notes * llm check * Update build/transfers/native-token-transfers/deployment-process/deploy-to-solana.md Co-authored-by: Erin Shaben * update based on feedback * llm check * action orientated link * llm check --------- Co-authored-by: Erin Shaben * Martinh/settlement grammar fix (#391) * fix(docs): fix grammar in unified liquidity paragraph (#390) * grammarly check * llm check --------- Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> * remove Connect from product comparison table (#396) * remove Connect from product comparison table * llms check --------- Co-authored-by: Ilaria Enache * Staked rpc comment & feature matrix adjustment (#402) * staked rpc comment for ntt solana deploy * adjust comment * adjust feature support matrix for sui & aptos cctp * re-generate llms files * Martinh/tutorial supported chains (#400) * update supported chains in tutorial * llm check --------- Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * update sdk to latest version (#399) * Martinh/update supported networks (#383) * add tables * add multigov compatible chains * ntt supported chains * update connect supported chains * llm check * automated table creation for supported blockchains by product * llm check * update table titles * llm check * update supported networks * llm check * update title * llm check * Update build/start-building/supported-networks.md Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> * update metadata description and title * llm check * llm check * supported chains per product in single snippets * llm check * update supported chains for token bridge and cctp * llm check * remove extre symbol at the end of tables * llm check --------- Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> * fix spacing (#416) * fix spacing * llms generation * Message fee (#415) * add messageFee value to relevant functions * remove comment * llms check --------- Co-authored-by: Ilaria Enache * Martinh/update sdk v1.19.0 (#406) * update sdk to latest version * add new chain via npm run generate * update ntt and multigov supported chains tables * llm check * support for seievm mainnet in sdk v1.20.0 (#417) * support for seievm mainnet * bump sdk variable to v1.20.0 * generate llms --------- Co-authored-by: Erin Shaben * rollback example changes (#418) * rollback example changes * update llms * get rid of all the old pages - delete old files - move any remaining content that is still relevant to a new home * fix links * update llms * update llms * delete llms * add llms back --------- Co-authored-by: Martin Hofmann Co-authored-by: Dawn Kelly <83190195+dawnkelly09@users.noreply.github.com> Co-authored-by: evgeniko <97796468+evgeniko@users.noreply.github.com> Co-authored-by: Suhas A <113137561+suhasamaresh@users.noreply.github.com> Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Ilaria Enache --- ..build/core-messaging/index.md | 39 - ..build/multigov/index.md | 84 - ..build/queries/overview.md | 100 - ..build/queries/use-queries.md | 180 - ..build/start-building/use-cases.md | 279 - ..build/transfers/connect/index.md | 66 - ..build/transfers/connect/overview.md | 80 - .../deployment-process/installation.md | 83 - .../transfers/native-token-transfers/index.md | 47 - ..learn/governance/overview.md | 38 - ..learn/transfers/cctp.md | 46 - ..learn/transfers/index.md | 72 - .../native-token-transfers/deployment.md | 29 - .../native-token-transfers/overview.md | 69 - ..learn/transfers/settlement/overview.md | 44 - ..learn/transfers/token-bridge.md | 66 - .../use-queries/eth-call-initial-request.txt | 1 - .../use-queries/eth-call-initial-response.txt | 5 - .../build/queries/use-queries/query-demo.sol | 137 - .../query-proxy-query-response.jsx | 4 - .../query-request-with-api-key.jsx | 8 - .../build/queries/use-queries/test-full.jsx | 65 - .../connect/overview/cdn-with-version.html | 12 - .../build/transfers/connect/overview/cdn.html | 12 - .../transfers/connect/overview/import-v0.js | 7 - .../transfers/connect/overview/import-v1.js | 5 - .../guides/cctp-contracts}/CCTPReceiver.sol | 0 .../guides/cctp-contracts}/CCTPSender.sol | 0 .../cctp-contracts}/CircleIntegration.sol | 0 .../cctp-contracts}/MessageTransmitter.sol | 0 .../guides/cctp-contracts}/TokenMessenger.sol | 0 .../guides/cctp-contracts}/TokenMinter.sol | 0 .../cctp-contracts}/receivePayloadAndUSDC.sol | 0 .../cctp-contracts}/sendCrossChainDeposit.sol | 0 .../sendUSDCWithPayloadToEvm.sol | 0 .../guides/hosted-version/hosted-1.js} | 3 + .../connect/guides/hosted-version/hosted-2.js | 22 + .../cli => tools/cli/get-started}/aptos.txt | 0 .../cli/get-started}/edit-vaa.txt | 0 .../cli => tools/cli/get-started}/evm.txt | 0 .../cli/get-started}/fetch-vaa-example.txt | 0 .../cli/get-started}/generate.txt | 0 .../cli/get-started}/guardian-upgrade.txt | 0 .../cli/get-started}/info-response.txt | 0 .../cli => tools/cli/get-started}/info.txt | 0 .../cli => tools/cli/get-started}/near.txt | 0 .../cli => tools/cli/get-started}/parse.txt | 0 .../cli => tools/cli/get-started}/recover.txt | 0 .../cli => tools/cli/get-started}/status.txt | 0 .../cli => tools/cli/get-started}/submit.txt | 0 .../cli => tools/cli/get-started}/sui.txt | 0 .../get-started}/token-attestation-vaa.txt | 0 .../cli/get-started}/transfer.txt | 0 .../get-started}/vaa-generation-example.txt | 0 .../cli/get-started}/verify-vaa.txt | 0 .../core-messaging-timeline.json | 27 - .../transfers/connect/connect-timeline.json | 17 - .../ntt/ntt-deployment-process-timeline.json | 22 - .../cctp-contracts}/DepositForBurn-event.md | 0 .../cctp-contracts}/MessageSent-event.md | 0 .../connect/overview/connect-timeline.json | 0 .../ntt/overview/ntt-timeline.json | 0 .../token-bridge/token-bridge-diagram.webp | Bin 4243584 -> 0 bytes llms-files/llms-basics.txt | 446 +- llms-files/llms-connect.txt | 706 +- llms-files/llms-multigov.txt | 575 +- llms-files/llms-ntt.txt | 1418 +- llms-files/llms-queries.txt | 970 +- llms-files/llms-relayers.txt | 443 +- llms-files/llms-settlement.txt | 492 +- llms-files/llms-solidity-sdk.txt | 683 +- llms-files/llms-token-bridge.txt | 914 +- llms-files/llms-transfer.txt | 3975 +- llms-files/llms-typescript-sdk.txt | 1506 +- llms-full.txt | 31331 ++++++++-------- llms.txt | 37 +- products/cctp-bridge/guides/.pages | 2 +- .../cctp-bridge/guides/cctp-contracts.md | 34 +- products/cctp-bridge/guides/transfer-usdc.md | 1 - products/connect/get-started.md | 15 +- products/connect/guides/.pages | 1 + products/connect/guides/hosted-version.md | 42 + products/connect/overview.md | 2 +- products/native-token-transfers/.pages | 1 - products/native-token-transfers/faqs.md | 27 +- products/native-token-transfers/guides/.pages | 6 +- .../guides}/post-deployment.md | 0 .../troubleshoot.md} | 2 +- products/native-token-transfers/overview.md | 2 +- .../reference/cli-commands.md | 44 +- .../reference}/managers-transceivers.md | 0 products/products.md | 6 +- {..learn => products/reference}/glossary.md | 0 products/token-bridge/guides/.pages | 2 +- .../guides/token-bridge-contracts.md | 2 +- .../guides/transfer-wrapped-assets.md | 1 - tools/.pages | 1 + tools/cli/.pages | 3 + .../cli.md => tools/cli/get-started.md | 76 +- {..build/toolkit => tools}/dev-env.md | 0 {..build/toolkit => tools}/faqs.md | 0 101 files changed, 18942 insertions(+), 26493 deletions(-) delete mode 100644 ..build/core-messaging/index.md delete mode 100644 ..build/multigov/index.md delete mode 100644 ..build/queries/overview.md delete mode 100644 ..build/queries/use-queries.md delete mode 100644 ..build/start-building/use-cases.md delete mode 100644 ..build/transfers/connect/index.md delete mode 100644 ..build/transfers/connect/overview.md delete mode 100644 ..build/transfers/native-token-transfers/deployment-process/installation.md delete mode 100644 ..build/transfers/native-token-transfers/index.md delete mode 100644 ..learn/governance/overview.md delete mode 100644 ..learn/transfers/cctp.md delete mode 100644 ..learn/transfers/index.md delete mode 100644 ..learn/transfers/native-token-transfers/deployment.md delete mode 100644 ..learn/transfers/native-token-transfers/overview.md delete mode 100644 ..learn/transfers/settlement/overview.md delete mode 100644 ..learn/transfers/token-bridge.md delete mode 100644 .snippets/code/build/queries/use-queries/eth-call-initial-request.txt delete mode 100644 .snippets/code/build/queries/use-queries/eth-call-initial-response.txt delete mode 100644 .snippets/code/build/queries/use-queries/query-demo.sol delete mode 100644 .snippets/code/build/queries/use-queries/query-proxy-query-response.jsx delete mode 100644 .snippets/code/build/queries/use-queries/query-request-with-api-key.jsx delete mode 100644 .snippets/code/build/queries/use-queries/test-full.jsx delete mode 100644 .snippets/code/build/transfers/connect/overview/cdn-with-version.html delete mode 100644 .snippets/code/build/transfers/connect/overview/cdn.html delete mode 100644 .snippets/code/build/transfers/connect/overview/import-v0.js delete mode 100644 .snippets/code/build/transfers/connect/overview/import-v1.js rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/CCTPReceiver.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/CCTPSender.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/CircleIntegration.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/MessageTransmitter.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/TokenMessenger.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/TokenMinter.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/receivePayloadAndUSDC.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/sendCrossChainDeposit.sol (100%) rename .snippets/code/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/sendUSDCWithPayloadToEvm.sol (100%) rename .snippets/code/{build/transfers/connect/overview/hosted.js => products/connect/guides/hosted-version/hosted-1.js} (72%) create mode 100644 .snippets/code/products/connect/guides/hosted-version/hosted-2.js rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/aptos.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/edit-vaa.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/evm.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/fetch-vaa-example.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/generate.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/guardian-upgrade.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/info-response.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/info.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/near.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/parse.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/recover.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/status.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/submit.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/sui.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/token-attestation-vaa.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/transfer.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/vaa-generation-example.txt (100%) rename .snippets/code/{build/toolkit/cli => tools/cli/get-started}/verify-vaa.txt (100%) delete mode 100644 .snippets/text/build/core-messaging/core-messaging-timeline.json delete mode 100644 .snippets/text/build/transfers/connect/connect-timeline.json delete mode 100644 .snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json rename .snippets/text/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/DepositForBurn-event.md (100%) rename .snippets/text/{build/transfers/cctp => products/cctp-bridge/guides/cctp-contracts}/MessageSent-event.md (100%) rename .snippets/text/products/{reference => }/connect/overview/connect-timeline.json (100%) rename .snippets/text/products/{reference => }/ntt/overview/ntt-timeline.json (100%) delete mode 100644 images/learn/transfers/token-bridge/token-bridge-diagram.webp rename ..build/transfers/cctp.md => products/cctp-bridge/guides/cctp-contracts.md (94%) delete mode 100644 products/cctp-bridge/guides/transfer-usdc.md create mode 100644 products/connect/guides/hosted-version.md rename {..build/transfers/native-token-transfers/deployment-process => products/native-token-transfers/guides}/post-deployment.md (100%) rename products/native-token-transfers/{troubleshooting.md => guides/troubleshoot.md} (99%) rename {..build/transfers/native-token-transfers => products/native-token-transfers/reference}/managers-transceivers.md (100%) rename {..learn => products/reference}/glossary.md (100%) rename ..build/transfers/token-bridge.md => products/token-bridge/guides/token-bridge-contracts.md (99%) delete mode 100644 products/token-bridge/guides/transfer-wrapped-assets.md create mode 100644 tools/cli/.pages rename ..build/toolkit/cli.md => tools/cli/get-started.md (83%) rename {..build/toolkit => tools}/dev-env.md (100%) rename {..build/toolkit => tools}/faqs.md (100%) diff --git a/..build/core-messaging/index.md b/..build/core-messaging/index.md deleted file mode 100644 index bfaa5a14e..000000000 --- a/..build/core-messaging/index.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Core Messaging Layer Contracts -description: Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. ---- - -# Core Messaging - -Wormhole-deployed relayers and Core Contracts are essential for sending and receiving multichain messages. Learning to work directly with these building blocks offers a deeper understanding of Wormhole and increased control and customization options. - -Follow the links below for how-to guides about using Core Contracts and Wormhole-deployed relayers to send, receive, validate, and track multichain messages. - -## Simplified Message Flow - - -Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. - -[timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] - -## Next Steps - -
- -- :octicons-tools-16:{ .lg .middle} **Get Started with Core Contracts** - - --- - - Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. - - [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) - -- :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** - - --- - - Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. - - [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) - -
diff --git a/..build/multigov/index.md b/..build/multigov/index.md deleted file mode 100644 index 0a40adf15..000000000 --- a/..build/multigov/index.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Getting Started with MultiGov -description: Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -categories: MultiGov ---- - -# MultiGov - -## Begin the MultiGov Integration Process - -Take the following steps to get started with a MultiGov integration: - -1. Evaluate if [MultiGov](/docs/learn/governance/) meets your cross-chain governance needs -2. Fill out the intake form on the [Tally website](https://www.tally.xyz/get-started){target=\_blank} -3. The Tally team will review your application and contact you to discuss implementation details -4. Work with the Tally team to customize and deploy MultiGov for your specific use case - -## Start Building - -
- -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** - - --- - - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** - - --- - - Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** - - --- - - Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - -- :octicons-question-16:{ .lg .middle } **Technical FAQs** - - --- - - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) - -
- -## Additional Resources - -
- -- :octicons-book-16:{ .lg .middle } **What is MultiGov?** - - --- - - Need to familiarize yourself with MultiGov? Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. - - [:custom-arrow: Learn the basics](/docs/learn/governance/) - -- :octicons-checklist-16:{ .lg .middle } **Tutorials** - - --- - - Access step-by-step tutorials for executing cross-chain governance actions, including treasury management proposals with MultiGov. - - [:custom-arrow: Learn by building](/docs/tutorials/multigov/) - -
diff --git a/..build/queries/overview.md b/..build/queries/overview.md deleted file mode 100644 index 2b532bf6b..000000000 --- a/..build/queries/overview.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Queries Overview -description: Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -categories: Queries ---- - -# Queries Overview {: #queries-overview } - -Wormhole Guardians, who run full nodes for various connected chains, facilitate a new cross-chain query service that allows for on-demand attested responses to queries, bypassing the inefficiencies of traditional transaction-based data retrieval. This method is faster and cost-effective, eliminating the need for gas payments and transaction finality wait times. - -!!! note - Queries are currently in closed beta, though you can start developing today. Check out [Use Queries](/docs/build/queries/use-queries/){target=\_blank} and reach out to [Join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data. The current implementation provides integrators with a simple REST endpoint to initiate an off-chain request via a proxy. The proxy then forwards the request to the Guardians and gathers a quorum of responses. The result returns the encoded response, including the request details and the Guardian signatures. The request validation performed by the query module includes a three step process that involves verifying the signature to ensure it has the correct prefix, confirming that the signer is authorized to execute query requests, and validating the legitimacy of all per-chain requests contained in the query. You can read more about Queries in the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank}. - -## The Flow of a Query {: #the-flow-of-a-query} - -The general overview of a query's flow is as follows: an off-chain process sends HTTPS query requests to a Query Proxy, which validates and forwards them to the Guardians; these Guardians independently validate, sign, and return the response, with the entire process typically taking less than a second. - -![The architecture flow of a query](/docs/images/build/queries/overview/overview-1.webp) - -The step-by-step flow of a query is as follows: - -1. An off-chain process initiates a query request via HTTPS to the query proxy (or Query Server) -2. The query proxy validates the request and forwards it to the Guardians via a gossip network -3. The Guardians independently validate the request, make the requisite RPC calls, verify the results, sign, and gossip a response back to the Query Proxy -4. The Query Proxy aggregates the results and returns a response when it reaches a quorum of two-thirds or more of the current Guardian set - the exact quorum requirements as the core bridge -5. The off-chain process can then submit these requests to an on-chain contract which should verify the signatures and validate the request before processing the result - -In this flow, the Query Proxy is a permissioned but trustless part of the protocol. In most cases, this entire process takes less than one second. If a request is invalid or cannot be processed by the Guardians, they will retry for up to one minute before timing out. Requests can be batched to have the Guardians make multiple calls to multiple networks. This can further reduce overhead for processing query responses on-chain. Up to 255 queries can be batched together, with certain types allowing for batching themselves. - -## Supported Query Types {: #supported-query-types} - -There are currently five supported types of queries. See [the white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank} for more details on each. - -### eth_call {: #eth-call} - -This query type is effectively an equivalent of [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a block specified by number or hash. - -Calls are batched to allow specifying multiple calls (even to multiple contracts) against the same block. These calls are included in a single batch RPC call, simplifying on-chain verification. Up to 255 calls may be batched in an single `eth_call` query. - -The result contains the specified block number, hash, timestamp, and the call result. - -### eth_call By Timestamp {: #eth-call-by-timestamp} - -This query type is similar to `eth_call` but targets a timestamp instead of a specific `block_id`. This can be useful when forming requests based on uncorrelated data, such as requiring data from another chain based on the block timestamp of a given chain. - -The result also contains the target and block details with the following enforced conditions: `target_block.timestamp <= target_time < following_block.timestamp` and `following_block_num - 1 == target_block_num`. - -### eth_call With Finality {: #eth-call-with-finality} - -This query type is similar to `eth_call` but ensures that the specified block has reached the specified finality before returning the query results. The finality may be `finalized` or `safe.` Note that if a chain doesn't natively support the `safe` tag, this will be equivalent to `finalized.` - -### sol_account {: #sol_account} - -This query is used to read data for one or more accounts on Solana, akin to [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank}. - -### sol_pda {: #sol_pda} - -This query is used to read data for one or more [Program Derived Addresses(PDA)](https://www.anchor-lang.com/docs/pdas){target=\_blank} on Solana, akin to calling [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} on the result of `PublicKey.findProgramAddressSync(seeds, programId).` This query is helpful for times when you want to more generally read accounts owned by a program and verify the derivation on another chain, like how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. - -## Supported Chains {: #supported-chains} - -The following table provides expected support based on testing. However, the success of any given query is based on the success of the underlying call on each Guardian’s RPC node. - -For example, many chains have implementations forked from [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which keeps 128 blocks of state in memory by default (without running in archive mode). While this is good for about 25 minutes of history on Ethereum Mainnet, it is only about three minutes on Optimism. While Guardian nodes can be expected to have access to recent state, there are currently no guarantees of how far back in history they have access to. - -### Mainnet {: #mainnet} - -| Chain | Wormhole Chain ID | eth_call | By Timestamp | With Finality | Expected History | -|:-------------:|:-----------------:|:--------:|:------------------:|:-------------:|:----------------:| -| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | -| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | -| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | -| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | -| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | -| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | -| Karura | 11 | ✅ | ✅ | ✅ | archive | -| Acala | 12 | ✅ | ✅ | ✅ | archive | -| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | -| Celo | 14 | ✅ | ℹ️ hints required\* | ✅ | 128 blocks | -| Moonbeam | 16 | ✅ | ℹ️ hints required\* | ✅ | 256 blocks | -| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | -| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | -| Base | 30 | ✅ | ✅ | ✅ | archive | - -\*`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. - -## Next Steps {: #next-steps} - -Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. - -Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. - -You can also check out the following examples of applications that make use of Wormhole Queries: - -- [Basic demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} \ No newline at end of file diff --git a/..build/queries/use-queries.md b/..build/queries/use-queries.md deleted file mode 100644 index 0a5ebcdb4..000000000 --- a/..build/queries/use-queries.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: Use Queries -description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -categories: Queries ---- - -# Use Queries - -You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. - -This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. - -## RPC Basics - -Before digging into anything Queries-specific, this page will look at how to make an [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a public Ethereum RPC. Suppose you'd like to query the WETH contract for its total supply; before making a request, you need some information about the contract you want to call, including: - -- **To** - the contract to call. WETH is [0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2){target=\_blank} -- **Data** - the method identifier and ABI-encoded parameters, which can be obtained as follows: `web3.eth.abi.encodeFunctionSignature("totalSupply()")` which yields `0x18160ddd` -- **Block ID** - the block number, hash, or tag. Tag options include `latest,` `safe,` or `finalized` - -The prepared curl request is as follows: - -```bash title="eth_call JSON-RPC request" ---8<-- 'code/build/queries/use-queries/eth-call-initial-request.txt' -``` - -And the corresponding response is: - -```bash title="eth_call JSON-RPC reponse" ---8<-- 'code/build/queries/use-queries/eth-call-initial-response.txt' -``` - -Converting the returned value of the executed call from hexidecimal results in the value `3172615244782286193073777`. You can compare your result to the [**Read Contract**](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#readContract){target=\_blank} tab in Etherscan. Your result will be different as WETH is minted/burned over time. - -## Construct a Query {: #construct-a-query} - -You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. - -```jsx -npm i @wormhole-foundation/wormhole-query-sdk axios -``` - -In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. - -You can request the latest block from a public node using `eth_getBlockByNumber`. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:12:12' ---8<-- 'code/build/queries/use-queries/test-full.jsx:19:26' -``` - -Then construct the call data. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:13:16' -``` - -Finally, put it all together in a `QueryRequest`. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:44:53' -``` - -This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:54:54' -// { -// "nonce": 0, -// "requests": [ -// { -// "chainId": 2, -// "query": { -// "callData": [ -// { -// "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", -// "data": "0x18160ddd" -// } -// ], -// "blockTag": "0x11e9068" -// } -// } -// ], -// "version": 1 -// } -``` - -## Mock a Query - -For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:55:57' -// { -// signatures: ['...'], -// bytes: '...' -// } -``` - -This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx:58:64' -// Mock Query Result: 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee (3172556167631284394053614) -``` - -Testing this all together might look like the following: - -```jsx ---8<-- 'code/build/queries/use-queries/test-full.jsx' -``` - -### Fork Testing - -It is common to test against a local fork of Mainnet with something like - -```jsx -anvil --fork-url https://ethereum.publicnode.com -``` - -In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. - -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. - -```jsx -npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe -``` - -If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. - -## Make a Query Request - -The standardized means of making a `QueryRequest` with an API key is as follows: - -```jsx ---8<-- 'code/build/queries/use-queries/query-request-with-api-key.jsx' -``` - -Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. - -A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` - -A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` - -## Verify a Query Response On-Chain - -A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: - -```bash -forge install wormhole-foundation/wormhole-solidity-sdk -``` - -Broadly, using a query response on-chain comes down to three main steps: - - 1. Parse and verify the query response - 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract - 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: - - Is the request against the expected chain? - - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing - - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks - - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases - - Is the result of the expected length for the expected result type? - 4. Run `abi.decode` on the result - -See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. - -??? code "View the complete `QueryDemo`" - ```solidity - --8<-- 'code/build/queries/use-queries/query-demo.sol' - ``` - -## Submit a Query Response On-Chain - -The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. - -This example submits the transaction to the demo contract: - -```jsx ---8<-- 'code/build/queries/use-queries/query-proxy-query-response.jsx' -``` diff --git a/..build/start-building/use-cases.md b/..build/start-building/use-cases.md deleted file mode 100644 index f1ecdbd64..000000000 --- a/..build/start-building/use-cases.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
-
- -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
-
- -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
-
- - -
-
- -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
-
- - -
-
- -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
-
- - -
-
- -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
-
- -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
-
- -
-
- -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
-
- - -
-
- -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
-
- -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
-
- - -
-
- -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
-
- - -
-
- -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
-
- - -
-
- -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
-
- - -
-
- -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
-
- - -
-
- -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
-
- -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
-
- - -
-
- -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
-
- -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
-
- - -
-
- -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
-
- -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
-
\ No newline at end of file diff --git a/..build/transfers/connect/index.md b/..build/transfers/connect/index.md deleted file mode 100644 index b53eb233d..000000000 --- a/..build/transfers/connect/index.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. - -## Build with Connect - -[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] - -## See It In Action - -Wormhole Connect is deployed live in several production apps. Here are a few: - -- [Portal Bridge](https://portalbridge.com/){target=\_blank} -- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} -- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} - -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). - -## Next Steps - -
- -- :octicons-tools-16:{ .lg .middle} **Get Started Now** - - --- - - Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. - - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) - -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** - - --- - - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - - - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - - -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** - - --- - - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** - - --- - - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) - -
- - - diff --git a/..build/transfers/connect/overview.md b/..build/transfers/connect/overview.md deleted file mode 100644 index 1d1a585d5..000000000 --- a/..build/transfers/connect/overview.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -## Introduction {: #introduction } - -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. - -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. - -## Features {: #features } - -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: - -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination - -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. - -## Integrate Connect {: #integrate-connect } - -### Import Directly into a React App {: #import-directly-into-a-react-app} - -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - -```bash -npm i @wormhole-foundation/wormhole-connect -``` - -Now you can import the React component: - -```ts ---8<-- 'code/build/transfers/connect/overview/import-v1.js' -``` - -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} - -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. - -```ts title="v1.x" ---8<-- 'code/build/transfers/connect/overview/hosted.js' -``` - -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. - -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. - - ```html - --8<-- 'code/build/transfers/connect/overview/cdn.html' - ``` - - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: - - ```html - --8<-- 'code/build/transfers/connect/overview/cdn-with-version.html' - ``` - -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. - -## Configuration {: #configuration} - -This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. - -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: - - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available - -For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. diff --git a/..build/transfers/native-token-transfers/deployment-process/installation.md b/..build/transfers/native-token-transfers/deployment-process/installation.md deleted file mode 100644 index cc1aa8d33..000000000 --- a/..build/transfers/native-token-transfers/deployment-process/installation.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- - -# Install the Native Token Transfers CLI - -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. - -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - -
- -## Install NTT CLI - -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: - -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} - -Follow these steps to install the NTT CLI: - -1. Run the installation command in your terminal: - - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` - -2. Verify the NTT CLI is installed: - - ```bash - ntt --version - ``` - -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI - -## Update NTT CLI - -To update an existing NTT CLI installation, run the following command in your terminal: - -```bash -ntt update -``` - -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. - -For local development, you can update your CLI version from a specific branch or install from a local path. - -To install from a specific branch, run: - -```bash -ntt update --branch foo -``` - -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` - -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. - -## Where to Go Next - -
- - -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** - - --- - - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** - - --- - - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) - -
diff --git a/..build/transfers/native-token-transfers/index.md b/..build/transfers/native-token-transfers/index.md deleted file mode 100644 index 2abe026fb..000000000 --- a/..build/transfers/native-token-transfers/index.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- - -# Native Token Transfers - -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. - -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. - -## Quickstart - -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: - -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] - -## Deploy NTTs with Launchpad - -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. - -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. - -## Additional Resources - -
- -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** - - --- - - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - -- :octicons-question-16:{ .lg .middle } **NTT FAQs** - - --- - - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) - -
diff --git a/..learn/governance/overview.md b/..learn/governance/overview.md deleted file mode 100644 index 594047b0f..000000000 --- a/..learn/governance/overview.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: MultiGov Overview -description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -categories: MultiGov ---- - -# MultiGov: Cross-Chain Governance with Wormhole - -## Overview - -### What Is MultiGov and Why Is It Important? - -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. - -MultiGov is important because it: - -- **Increases participation** by allowing token holders from multiple chains to engage in governance -- **Enhances security** by leveraging Wormhole's robust cross-chain communication -- **Improves scalability** by integrating any chain supported by Wormhole -- **Enables unified governance** and coordinated decision-making across multiple networks - -### Key Features - -- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains -- **Cross-chain voting** - token holders on any integrated chain can cast votes -- **Vote aggregation** - votes from all chains are collected and tallied on the hub -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Wormhole integration** - secure and reliable cross-chain communication -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain - -### High-Level Architecture Diagram - -The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. - -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. - - -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) diff --git a/..learn/transfers/cctp.md b/..learn/transfers/cctp.md deleted file mode 100644 index 9d3ccad5d..000000000 --- a/..learn/transfers/cctp.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Circle's CCTP Bridge -description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -categories: Transfer ---- - -# Circle's CCTP Bridge - -Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. - -While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: - -- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves -- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain -- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer - -!!! note - Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. - -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. - -## Automatic Relaying - -To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. - -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. - -The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. - -| Chain | Fee | -|:---------------:|:---------------:| -| Ethereum | 1.0 USDC | -| Everything else | 0.1 USDC | - - - -## Native Gas Drop Off - -Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. - -The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. - - \ No newline at end of file diff --git a/..learn/transfers/index.md b/..learn/transfers/index.md deleted file mode 100644 index bdd546a2c..000000000 --- a/..learn/transfers/index.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Multichain Transfers -description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -categories: Transfer ---- - -# Multichain Transfers - -These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. - -Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: - -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset -- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism - -## Compare Transfer Products - -A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: - -### NTT vs. Token Bridge - -Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. - -- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains -- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases - -
- -| Supports | NTT | Token Bridge | -|---------------------------|--------------------|--------------------| -| Message Payload | :white_check_mark: | :white_check_mark: | -| Wrapped Assets | :x: | :white_check_mark: | -| Native Assets | :white_check_mark: | :x: | -| Contract-Free Development | :x: | :white_check_mark: | -| User-Owned Contracts | :white_check_mark: | :x: | - -
- -In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: - -
- - -### Settlement - -Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. - -By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. - -## Additional Resources - -
- -- :octicons-tools-16:{ .lg .middle } **Product Comparison** - - --- - - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - - [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) - -- :octicons-book-16:{ .lg .middle } **Use Cases** - - --- - - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) - - -
diff --git a/..learn/transfers/native-token-transfers/deployment.md b/..learn/transfers/native-token-transfers/deployment.md deleted file mode 100644 index 27cd320a8..000000000 --- a/..learn/transfers/native-token-transfers/deployment.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- - -# Deployment Models - -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. - -## Hub-and-Spoke - -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain - -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - -## Burn-and-Mint - -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - -This model best suits new token deployments or projects willing to upgrade existing contracts. - -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain \ No newline at end of file diff --git a/..learn/transfers/native-token-transfers/overview.md b/..learn/transfers/native-token-transfers/overview.md deleted file mode 100644 index 033d3fae2..000000000 --- a/..learn/transfers/native-token-transfers/overview.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- - -# Native Token Transfers - -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - -## Introduction - -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. - -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. - -## Key Features - -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: - -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - -## Integration Paths - -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. - -### Native Token Transfers Framework - -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. - -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: - -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} - -### Token Bridge - -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains - -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. - -## Supported Token Standards - -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. \ No newline at end of file diff --git a/..learn/transfers/settlement/overview.md b/..learn/transfers/settlement/overview.md deleted file mode 100644 index a5807d7a7..000000000 --- a/..learn/transfers/settlement/overview.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- - -# Wormhole Settlement Overview - -## Introduction - -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page \ No newline at end of file diff --git a/..learn/transfers/token-bridge.md b/..learn/transfers/token-bridge.md deleted file mode 100644 index 4da83ce04..000000000 --- a/..learn/transfers/token-bridge.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - -### How Does It Work? - -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. - -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). - -### Token Transfer Flow - -The transfer process is simple yet secure, involving a few key steps: - -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody - -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) - -### Key Features of the Token Bridge - -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - -### Message and Payload Structure - -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract - -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - -### Security and Authorization - -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - -### Portal Bridge - -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. diff --git a/.snippets/code/build/queries/use-queries/eth-call-initial-request.txt b/.snippets/code/build/queries/use-queries/eth-call-initial-request.txt deleted file mode 100644 index f9444496f..000000000 --- a/.snippets/code/build/queries/use-queries/eth-call-initial-request.txt +++ /dev/null @@ -1 +0,0 @@ -curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' \ No newline at end of file diff --git a/.snippets/code/build/queries/use-queries/eth-call-initial-response.txt b/.snippets/code/build/queries/use-queries/eth-call-initial-response.txt deleted file mode 100644 index 6884f7e7e..000000000 --- a/.snippets/code/build/queries/use-queries/eth-call-initial-response.txt +++ /dev/null @@ -1,5 +0,0 @@ -{ - "jsonrpc":"2.0", - "id":1, - "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" -} \ No newline at end of file diff --git a/.snippets/code/build/queries/use-queries/query-demo.sol b/.snippets/code/build/queries/use-queries/query-demo.sol deleted file mode 100644 index c893ae629..000000000 --- a/.snippets/code/build/queries/use-queries/query-demo.sol +++ /dev/null @@ -1,137 +0,0 @@ -// contracts/query/QueryDemo.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; -import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "wormhole-solidity-sdk/QueryResponse.sol"; - -error InvalidOwner(); -// @dev for the onlyOwner modifier -error InvalidCaller(); -error InvalidCalldata(); -error InvalidForeignChainID(); -error ObsoleteUpdate(); -error StaleUpdate(); -error UnexpectedResultLength(); -error UnexpectedResultMismatch(); - -/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. -contract QueryDemo is QueryResponse { - using BytesParsing for bytes; - - struct ChainEntry { - uint16 chainID; - address contractAddress; - uint256 counter; - uint256 blockNum; - uint256 blockTime; - } - - address private immutable owner; - uint16 private immutable myChainID; - mapping(uint16 => ChainEntry) private counters; - uint16[] private foreignChainIDs; - - bytes4 public GetMyCounter = bytes4(hex"916d5743"); - - constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { - if (_owner == address(0)) { - revert InvalidOwner(); - } - owner = _owner; - - myChainID = _myChainID; - counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); - } - - // updateRegistration should be used to add the other chains and to set / update contract addresses. - function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { - if (counters[_chainID].chainID == 0) { - foreignChainIDs.push(_chainID); - counters[_chainID].chainID = _chainID; - } - - counters[_chainID].contractAddress = _contractAddress; - } - - // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. - function getMyCounter() public view returns (uint256) { - return counters[myChainID].counter; - } - - // getState() returns this chain's view of all the counters. It is meant to be used in the front end. - function getState() public view returns (ChainEntry[] memory) { - ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); - ret[0] = counters[myChainID]; - uint256 length = foreignChainIDs.length; - - for (uint256 i = 0; i < length;) { - ret[i + 1] = counters[foreignChainIDs[i]]; - unchecked { - ++i; - } - } - - return ret; - } - - // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. - function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { - ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); - uint256 numResponses = r.responses.length; - if (numResponses != foreignChainIDs.length) { - revert UnexpectedResultLength(); - } - - for (uint256 i = 0; i < numResponses;) { - // Create a storage pointer for frequently read and updated data stored on the blockchain - ChainEntry storage chainEntry = counters[r.responses[i].chainId]; - if (chainEntry.chainID != foreignChainIDs[i]) { - revert InvalidForeignChainID(); - } - - EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); - - // Validate that update is not obsolete - validateBlockNum(eqr.blockNum, chainEntry.blockNum); - - // Validate that update is not stale - validateBlockTime(eqr.blockTime, block.timestamp - 300); - - if (eqr.result.length != 1) { - revert UnexpectedResultMismatch(); - } - - // Validate addresses and function signatures - address[] memory validAddresses = new address[](1); - bytes4[] memory validFunctionSignatures = new bytes4[](1); - validAddresses[0] = chainEntry.contractAddress; - validFunctionSignatures[0] = GetMyCounter; - - validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); - - require(eqr.result[0].result.length == 32, "result is not a uint256"); - - chainEntry.blockNum = eqr.blockNum; - chainEntry.blockTime = eqr.blockTime / 1_000_000; - chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); - - unchecked { - ++i; - } - } - - counters[myChainID].blockNum = block.number; - counters[myChainID].blockTime = block.timestamp; - counters[myChainID].counter += 1; - } - - modifier onlyOwner() { - if (owner != msg.sender) { - revert InvalidOwner(); - } - _; - } -} \ No newline at end of file diff --git a/.snippets/code/build/queries/use-queries/query-proxy-query-response.jsx b/.snippets/code/build/queries/use-queries/query-proxy-query-response.jsx deleted file mode 100644 index ab1612093..000000000 --- a/.snippets/code/build/queries/use-queries/query-proxy-query-response.jsx +++ /dev/null @@ -1,4 +0,0 @@ -const tx = await contract.updateCounters( - `0x${response.data.bytes}`, - signaturesToEvmStruct(response.data.signatures) -); \ No newline at end of file diff --git a/.snippets/code/build/queries/use-queries/query-request-with-api-key.jsx b/.snippets/code/build/queries/use-queries/query-request-with-api-key.jsx deleted file mode 100644 index 2e37105b4..000000000 --- a/.snippets/code/build/queries/use-queries/query-request-with-api-key.jsx +++ /dev/null @@ -1,8 +0,0 @@ -const serialized = request.serialize(); -const proxyResponse = (await axios.post)( - QUERY_URL, - { - bytes: Buffer.from(serialized).toString('hex'), - }, - { headers: { 'X-API-Key': YOUR_API_KEY } } -); diff --git a/.snippets/code/build/queries/use-queries/test-full.jsx b/.snippets/code/build/queries/use-queries/test-full.jsx deleted file mode 100644 index 5ea02e6b3..000000000 --- a/.snippets/code/build/queries/use-queries/test-full.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import { - EthCallData, - EthCallQueryRequest, - EthCallQueryResponse, - PerChainQueryRequest, - QueryProxyMock, - QueryRequest, - QueryResponse, -} from '@wormhole-foundation/wormhole-query-sdk'; -import axios from 'axios'; - -const rpc = 'https://ethereum.publicnode.com'; -const callData: EthCallData = { - to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; - -(async () => { - const latestBlock: string = ( - await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; - if (!latestBlock) { - console.error(`❌ Invalid block returned`); - return; - } - console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); - const targetResponse = await axios.post(rpc, { - method: 'eth_call', - params: [callData, latestBlock], - id: 1, - jsonrpc: '2.0', - }); - // console.log(finalizedResponse.data); - if (targetResponse.data.error) { - console.error(`❌ ${targetResponse.data.error.message}`); - } - const targetResult = targetResponse.data?.result; - console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); - // Form the query request - const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); - console.log(JSON.stringify(request, undefined, 2)); - const mock = new QueryProxyMock({ 2: rpc }); - const mockData = await mock.mock(request); - console.log(mockData); - const mockQueryResponse = QueryResponse.from(mockData.bytes); - const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -})(); \ No newline at end of file diff --git a/.snippets/code/build/transfers/connect/overview/cdn-with-version.html b/.snippets/code/build/transfers/connect/overview/cdn-with-version.html deleted file mode 100644 index 7ee5dd59f..000000000 --- a/.snippets/code/build/transfers/connect/overview/cdn-with-version.html +++ /dev/null @@ -1,12 +0,0 @@ - -
- - - - diff --git a/.snippets/code/build/transfers/connect/overview/cdn.html b/.snippets/code/build/transfers/connect/overview/cdn.html deleted file mode 100644 index 3b6696d11..000000000 --- a/.snippets/code/build/transfers/connect/overview/cdn.html +++ /dev/null @@ -1,12 +0,0 @@ - -
- - - - diff --git a/.snippets/code/build/transfers/connect/overview/import-v0.js b/.snippets/code/build/transfers/connect/overview/import-v0.js deleted file mode 100644 index 46f1b6fab..000000000 --- a/.snippets/code/build/transfers/connect/overview/import-v0.js +++ /dev/null @@ -1,7 +0,0 @@ -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - -function App() { - return ( - - ); -} \ No newline at end of file diff --git a/.snippets/code/build/transfers/connect/overview/import-v1.js b/.snippets/code/build/transfers/connect/overview/import-v1.js deleted file mode 100644 index 02604db36..000000000 --- a/.snippets/code/build/transfers/connect/overview/import-v1.js +++ /dev/null @@ -1,5 +0,0 @@ -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - -function App() { - return ; -} diff --git a/.snippets/code/build/transfers/cctp/CCTPReceiver.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/CCTPReceiver.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/CCTPReceiver.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/CCTPReceiver.sol diff --git a/.snippets/code/build/transfers/cctp/CCTPSender.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/CCTPSender.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/CCTPSender.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/CCTPSender.sol diff --git a/.snippets/code/build/transfers/cctp/CircleIntegration.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/CircleIntegration.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/CircleIntegration.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/CircleIntegration.sol diff --git a/.snippets/code/build/transfers/cctp/MessageTransmitter.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/MessageTransmitter.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/MessageTransmitter.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/MessageTransmitter.sol diff --git a/.snippets/code/build/transfers/cctp/TokenMessenger.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/TokenMessenger.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/TokenMessenger.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/TokenMessenger.sol diff --git a/.snippets/code/build/transfers/cctp/TokenMinter.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/TokenMinter.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/TokenMinter.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/TokenMinter.sol diff --git a/.snippets/code/build/transfers/cctp/receivePayloadAndUSDC.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/receivePayloadAndUSDC.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/receivePayloadAndUSDC.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/receivePayloadAndUSDC.sol diff --git a/.snippets/code/build/transfers/cctp/sendCrossChainDeposit.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/sendCrossChainDeposit.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/sendCrossChainDeposit.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/sendCrossChainDeposit.sol diff --git a/.snippets/code/build/transfers/cctp/sendUSDCWithPayloadToEvm.sol b/.snippets/code/products/cctp-bridge/guides/cctp-contracts/sendUSDCWithPayloadToEvm.sol similarity index 100% rename from .snippets/code/build/transfers/cctp/sendUSDCWithPayloadToEvm.sol rename to .snippets/code/products/cctp-bridge/guides/cctp-contracts/sendUSDCWithPayloadToEvm.sol diff --git a/.snippets/code/build/transfers/connect/overview/hosted.js b/.snippets/code/products/connect/guides/hosted-version/hosted-1.js similarity index 72% rename from .snippets/code/build/transfers/connect/overview/hosted.js rename to .snippets/code/products/connect/guides/hosted-version/hosted-1.js index fda1ac369..4067feee6 100644 --- a/.snippets/code/build/transfers/connect/overview/hosted.js +++ b/.snippets/code/products/connect/guides/hosted-version/hosted-1.js @@ -2,5 +2,8 @@ import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; // Existing DOM element where you want to mount Connect const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'bridge-container' not found"); +} wormholeConnectHosted(container); diff --git a/.snippets/code/products/connect/guides/hosted-version/hosted-2.js b/.snippets/code/products/connect/guides/hosted-version/hosted-2.js new file mode 100644 index 000000000..5ec41ada8 --- /dev/null +++ b/.snippets/code/products/connect/guides/hosted-version/hosted-2.js @@ -0,0 +1,22 @@ +import { + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; + +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'connect' not found"); +} + +wormholeConnectHosted(container, { + config: { + rpcs: { + // ... + } + }, + theme: { + background: { + default: '#004547', + } + } +}); \ No newline at end of file diff --git a/.snippets/code/build/toolkit/cli/aptos.txt b/.snippets/code/tools/cli/get-started/aptos.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/aptos.txt rename to .snippets/code/tools/cli/get-started/aptos.txt diff --git a/.snippets/code/build/toolkit/cli/edit-vaa.txt b/.snippets/code/tools/cli/get-started/edit-vaa.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/edit-vaa.txt rename to .snippets/code/tools/cli/get-started/edit-vaa.txt diff --git a/.snippets/code/build/toolkit/cli/evm.txt b/.snippets/code/tools/cli/get-started/evm.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/evm.txt rename to .snippets/code/tools/cli/get-started/evm.txt diff --git a/.snippets/code/build/toolkit/cli/fetch-vaa-example.txt b/.snippets/code/tools/cli/get-started/fetch-vaa-example.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/fetch-vaa-example.txt rename to .snippets/code/tools/cli/get-started/fetch-vaa-example.txt diff --git a/.snippets/code/build/toolkit/cli/generate.txt b/.snippets/code/tools/cli/get-started/generate.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/generate.txt rename to .snippets/code/tools/cli/get-started/generate.txt diff --git a/.snippets/code/build/toolkit/cli/guardian-upgrade.txt b/.snippets/code/tools/cli/get-started/guardian-upgrade.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/guardian-upgrade.txt rename to .snippets/code/tools/cli/get-started/guardian-upgrade.txt diff --git a/.snippets/code/build/toolkit/cli/info-response.txt b/.snippets/code/tools/cli/get-started/info-response.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/info-response.txt rename to .snippets/code/tools/cli/get-started/info-response.txt diff --git a/.snippets/code/build/toolkit/cli/info.txt b/.snippets/code/tools/cli/get-started/info.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/info.txt rename to .snippets/code/tools/cli/get-started/info.txt diff --git a/.snippets/code/build/toolkit/cli/near.txt b/.snippets/code/tools/cli/get-started/near.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/near.txt rename to .snippets/code/tools/cli/get-started/near.txt diff --git a/.snippets/code/build/toolkit/cli/parse.txt b/.snippets/code/tools/cli/get-started/parse.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/parse.txt rename to .snippets/code/tools/cli/get-started/parse.txt diff --git a/.snippets/code/build/toolkit/cli/recover.txt b/.snippets/code/tools/cli/get-started/recover.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/recover.txt rename to .snippets/code/tools/cli/get-started/recover.txt diff --git a/.snippets/code/build/toolkit/cli/status.txt b/.snippets/code/tools/cli/get-started/status.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/status.txt rename to .snippets/code/tools/cli/get-started/status.txt diff --git a/.snippets/code/build/toolkit/cli/submit.txt b/.snippets/code/tools/cli/get-started/submit.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/submit.txt rename to .snippets/code/tools/cli/get-started/submit.txt diff --git a/.snippets/code/build/toolkit/cli/sui.txt b/.snippets/code/tools/cli/get-started/sui.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/sui.txt rename to .snippets/code/tools/cli/get-started/sui.txt diff --git a/.snippets/code/build/toolkit/cli/token-attestation-vaa.txt b/.snippets/code/tools/cli/get-started/token-attestation-vaa.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/token-attestation-vaa.txt rename to .snippets/code/tools/cli/get-started/token-attestation-vaa.txt diff --git a/.snippets/code/build/toolkit/cli/transfer.txt b/.snippets/code/tools/cli/get-started/transfer.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/transfer.txt rename to .snippets/code/tools/cli/get-started/transfer.txt diff --git a/.snippets/code/build/toolkit/cli/vaa-generation-example.txt b/.snippets/code/tools/cli/get-started/vaa-generation-example.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/vaa-generation-example.txt rename to .snippets/code/tools/cli/get-started/vaa-generation-example.txt diff --git a/.snippets/code/build/toolkit/cli/verify-vaa.txt b/.snippets/code/tools/cli/get-started/verify-vaa.txt similarity index 100% rename from .snippets/code/build/toolkit/cli/verify-vaa.txt rename to .snippets/code/tools/cli/get-started/verify-vaa.txt diff --git a/.snippets/text/build/core-messaging/core-messaging-timeline.json b/.snippets/text/build/core-messaging/core-messaging-timeline.json deleted file mode 100644 index 47e11d538..000000000 --- a/.snippets/text/build/core-messaging/core-messaging-timeline.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "title": "[Get Started](/docs/products/messaging/get-started/)", - "content": "Get Started with Messaging", - "icon": ":fontawesome-solid-1:" - }, - { - "title": "[Send Messages](/docs/products/messaging/guides/core-contracts/#sending-messages)", - "content": "How-to send messages with Core Contracts.", - "icon": ":fontawesome-solid-2:" - }, - { - "title": "[Interact with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/#receive-a-message)", - "content": "How-to use Wormhole Relayer in your messaging workflow.", - "icon": ":fontawesome-solid-3:" - }, - { - "title": "[Receive Messages](/docs/products/messaging/guides/core-contracts/#receiving-messages)", - "content": "How-to verify and parse received messages.", - "icon": ":fontawesome-solid-4:" - }, - { - "title": "[Validate the Emitter](/docs/products/messaging/guides/core-contracts/#validating-the-emitter)", - "content": "How-to verify messages came from a trusted sender.", - "icon": ":fontawesome-solid-5:" - } -] \ No newline at end of file diff --git a/.snippets/text/build/transfers/connect/connect-timeline.json b/.snippets/text/build/transfers/connect/connect-timeline.json deleted file mode 100644 index ae528383f..000000000 --- a/.snippets/text/build/transfers/connect/connect-timeline.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "title": "[Integrate Connect](TODO)", - "content": "How-to install via npm package or use hosted CDN.", - "icon": ":fontawesome-solid-1:" - }, - { - "title": "[Configure data](/docs/products/connect/configuration/data/)", - "content": "How-to specify networks, RPCs, supported tokens, and more.", - "icon": ":fontawesome-solid-2:" - }, - { - "title": "[Customize styling](/docs/products/connect/configuration/theme/)", - "content": "How-to style your widget with color schemes, fonts, and layout options.", - "icon": ":fontawesome-solid-3:" - } -] diff --git a/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json b/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json deleted file mode 100644 index b40d42349..000000000 --- a/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "title": "[Install NTT CLI](/docs/build/transfers/native-token-transfers/deployment-process/installation/)", - "content": "The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs.", - "icon": ":fontawesome-solid-1:" - }, - { - "title": "[Configure NTTs](/docs/products/native-token-transfers/configuration/access-control/)", - "content": "Set NTT configuration options to manage Owner and Pauser access control roles and rate-limiting.", - "icon": ":fontawesome-solid-2:" - }, - { - "title": "[Deploy NTTs](/docs/products/native-token-transfers/guides/)", - "content": "Deploy your NTT to EVM chains and Solana.", - "icon": ":fontawesome-solid-3:" - }, - { - "title": "[Beyond Deployment](/docs/build/transfers/native-token-transfers/deployment-process/post-deployment/)", - "content": "Important considerations for managing your NTT integration after deployment. Find links to projects demonstrating NTT integration.", - "icon": ":fontawesome-solid-4:" - } -] \ No newline at end of file diff --git a/.snippets/text/build/transfers/cctp/DepositForBurn-event.md b/.snippets/text/products/cctp-bridge/guides/cctp-contracts/DepositForBurn-event.md similarity index 100% rename from .snippets/text/build/transfers/cctp/DepositForBurn-event.md rename to .snippets/text/products/cctp-bridge/guides/cctp-contracts/DepositForBurn-event.md diff --git a/.snippets/text/build/transfers/cctp/MessageSent-event.md b/.snippets/text/products/cctp-bridge/guides/cctp-contracts/MessageSent-event.md similarity index 100% rename from .snippets/text/build/transfers/cctp/MessageSent-event.md rename to .snippets/text/products/cctp-bridge/guides/cctp-contracts/MessageSent-event.md diff --git a/.snippets/text/products/reference/connect/overview/connect-timeline.json b/.snippets/text/products/connect/overview/connect-timeline.json similarity index 100% rename from .snippets/text/products/reference/connect/overview/connect-timeline.json rename to .snippets/text/products/connect/overview/connect-timeline.json diff --git a/.snippets/text/products/reference/ntt/overview/ntt-timeline.json b/.snippets/text/products/ntt/overview/ntt-timeline.json similarity index 100% rename from .snippets/text/products/reference/ntt/overview/ntt-timeline.json rename to .snippets/text/products/ntt/overview/ntt-timeline.json diff --git a/images/learn/transfers/token-bridge/token-bridge-diagram.webp b/images/learn/transfers/token-bridge/token-bridge-diagram.webp deleted file mode 100644 index cb3df65eb551bc26d1e79ded084230c2c7fd9901..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4243584 zcmZU)by(AX^gg`7=o}@@fYF`OjP4GRkPd+<-OA_|7+sPAA}BdPS~?^|sgY7D5&{ZH z?3thM_xF3A>w30p*Y(~%@4e4?opYaa?sLynM^iJT9|m}!p=xYtETiv@y%w2TaHaZa z?8m8tgmxzWP&fbZ9)sDm;unzULUd}JN8&7q^z=zZdi4cGdSN2>Q5)m%NS29@xa}R+ zObqVK?wTW0sZ*p`$`TUOQ#bh-=>AH{hbbR(iW-b4-Aq^4QTR3P)!}jI_~X)nwFqZl z#SDr~0PZF&q=vxoDe&H9PpQVDwO-5fzZ&9;{k+p$r1}AF`MxmMw;K*6R}3fWu4=As z-IUUMV^cojFP?sVBl*t6P3EKZfe-pO{J3uxFvX?JCDNSxw#ZM`i0Q@PRhY%Lt@xQ5 zaDB@{>R?!w#W0fF;MS#g<@MW2MhL&EDV7wqV{3kybeVyGl8;|*FWTo04 zWtRL9=pR>zxjwk=_vw7g4hz>N9dCAm1E%_6 z)R$5l604bgo)fQz;f6vrG`Ei84%tGqwDLvE-PHDwd=-=tG6(G*wU$Tk$^WAM8z_R$ z)xpz=d0;!C&ojY*dPDZWZeI@IoU91=5OUC6ey%$=0FS`;mAMHWG0~B z`~AH4y_11cy_>{>RU7xQKaowaa=P0WX6s6BZp}}7)b+y)e|>w+wRN%s^dyOrkS9b7 z(eSguG8OjfWHH_blV1|`!4 zwktueLp18@iM5xhGt%6kY;RVnj?KN{85-5Ss2kk`%}CHGXNc0qCj0)x!_sEDYt-S>Pfo^ffGfnWhG)Hn zjMw*kHT%eIANh2>qeE(P>8xbXV`Dp>`|gW2xIREfWUJ)`&nN162%%=LA{v+W{zZ}eTmvl(YSRgNlXVYYhK zsgk|@)Ktdcl@DqXzBpOYiqG{^MGXIyj;C1l1XIIH35L{d~XoH=#J zt*FCe`_rlm!A~nryl}2p8Y(&e#LUpr>`Jqqlh_#ec=6EjhB#z?)geqY&g-Db2`ndl5)9 z>ld9E-3?8zq6^cJS=49uFRw;QUVxJgzcG79bLLy<~t_*ui-q>x21qfgYEbPZfIn)^279RvS6@-(a%Vz z1xItC5n$}$aRwJ<{jV7e6Chd*;}Y2g6mWNV;t6cnIvza$1LjycI7knYa>magutdf@ znta+f>YI1Fo+EX;6ChBQZUUVcj{&<-sAqr~y`{n5&$W0tUv66;6N3@nyH9txdz}dhmE}uq##VE0{ zE5zyzVU*6gKM@!ZHK=0rs%7M5b z1aW630ltAMh&^=R;DUIVVP#+vqCfs2NL}5pkJ*pci!6)CuWtgvq1q@z2@p-1GTqlJ z|LH0czN@x8`3N;Ji8X+E(o%TB5;c(k0LV2yA-$iU4}v-L)#yVwgsks5uoP}Zuy?3s zYH>S=_Qw<8b7Zhb3C)ne`dx4`_VF4uAe0Z2W(@#|(1(cnm`x=-h#C%)CHs9G00*!> z`kUns7cfq6mkOO@pgcqsaO$BR`=XWz&{hY*)Uj_6NPR>dYb*@p z;`8`qv^|9fmXmQC@jwoSVG@WeIv<~Se_6J7nw}+6STQ1qK37q!3Y8B zuvl#bf^Z~>p92g8yp9?oeo_`BWHh1i(CO{&^M}!e9-EnW`UhlRvep5n00_=ZIPMt! z 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
Ik(ZY>ZTpB4_ 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ඒUM@%KbK7UkA$ZD`A^{e@$q!caBI8^F5N! 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
0` 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
  • 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

    Y@!%w*yKML~%X9R^ zHDfe7CBt3u$jxrt*VD&2YPjT$S3!cRh_bf>hNqf%doBh-XprLE6Y7U_(~ zi~AIoV&{&dm5=V7{dHu>SCPc{%I1Ihn<^HSQ2un>GTG>1 z#dE3m;Q$DMP}!fU4U^aR?D%#6!G(eEE^v*+9OK8SgD(hm9h^3;d=TVYwPG92AU62+ z<{IseHz(DfKsvZ@M!jRbT@@N*gt?)2A23PNGmp$Nf3@=tf%Nr*CH#|~m!+P(^91sB z5#w;cf6=P1J$qQ05(-Te>YW*F)EQLXdxu*r91i=7K7O|*94bHndgy(% z^>zF#lTs~yT(oiL8Si0E`~>-nF+jI;E7eg0C>$jXzJH(y;?0H~Z8p8zOtUvhZP{OE9B)GqX@=gBpY4eS20_aScS^?NgSxJ;&f{e=`{R^`pFqm3<-xHRAKx3y%e6j zHO;)Hxb5(dEH_GI44rtS2D;-=M?|$AN)oM1^)5-yK=-bHlKM<06;~*|SuZeB6mFR^ z=c>YY2f%jxW!8ns7K0>5dkPc>P{`~ss50AP>BBzg^#Ru>Z~|-?tQ!V7~435M@AwAZh7y= zS8(2;fOADX%o0f2~$nltG-EuDfUETb)7bH-S7mx1@x9(gUKMcQj zBIGrzBh+4CQQAU6A;_=?`K%^TxnC`ymCx>d(FFSHQz7axAP%lQY4PwG^;VPxuim4; zgRo~~tA=27bJ=(@lx)8d$me2Ho3{XmKzP4}hmwUeC0aiB!vyP})$Pe0D^nbVWJz5k?0IQH|I{(_xWKVvdBiY%oWXblVVqE7t{=`WkOVG&%fz zct`(4;~c`EBsJe~l{|o)JAQ&dB!r)%ZBd|$e4o0@w>vcMt8-U6*1Nbbn=w7(EJpJu z_tm&FSj1gVN^4ww8FAlN1h{`xthL|B{a}`#l0T_-tN38V_32u1M`=!>BhRu~--$ca zIk_`fR^1J%8qbh9;LNmw*YIBC&OloI@Q6yq{r7n~iVh;aAFK*Ra)iEP2~fb?HN=)Z zj$4lp{uRB;V1omNaC!H+_Yn2@V3Jmf{X986Ots*I>~0~qow7f>$C}i;fD{r#))wai zR~DBbT0X)ie(w6C_cruid2*6L7Z1dDgisSh10Duq@6fi4s@D%&hB^Uo0-RF*nkI(Z3JkC_ag^SK6Oam(z86YlAzjuIHqhkVPH=| zutoNcuBh-y2W3po%B&q9+u<+j{Zev2PGDER?)?%ugNEK|oj35rkW|)D>tg`4cYrbc z9~}dozfKFhuhu}$BC+wrlnm0O!K==Sljzi%NGy* zikY1fCrty<`aK|$IQs)~Bh}I5^2{Va86VvW;E{wff7#JxQC8q{-I2{U!~0b!A$3K@ zDRgoz^*ojDhJZc72dCA85vQ8gzrO`guhYh(X4c!Ce0!xycJQgr2}_=S-Wo!;zWrfB@)Gqv%B)Yo{zkoX5z3L^iK_4RJ5fF<_M6G+^sd9b zYfY8rak6AoYg1EuKR^kYA?u2B!7nm=>7D$5!fr>#&w)gyX0?3Gw&C+|e-AmW(O1L6 zlR$KUi2j*&Tlgu|-B9})j!uA6)-ay%M_VU@xkFd`{pq!%mIbGjP_(Nu2YVmA^LS6d zlV^F0^(?oGRMmc1uT6tY(f$DOj^9fgDtyvG8IzM84N7Q#r~2uS!>83q>b>-F2ycZ< zbv(f4-i^bM*5Up<^T$j1Ctw) zirhG0C)3-enMJfQ;paC;0&*dX-L|r^Ue9cPN_+1TN+Ca> zc=~HczxdfCG4u}3+Zgesrh%}8IrKWkHG5~h zcJiCi@0#}31rHQ}iwBB~#*i7K-U`K%XK+1v_u-apZP+gM1i9!Dy0nC`dT)q?i2)rwsePi?tw5I4M2hxkFNw^lNw+$|gpF=q zIsB-ITJPgs`}))ib?ZCtV+6Nc-j&iv7yb4d8!^WlSOQiK8qOz2%?k}vrAyXdXrwn_Pf^H;X2Z1Y+m`f=hk<&niDZ;wVdtB^OTvpY{)dNxHUUC zQI+BW*@aE4y~SSCbgYa$YRU3a8Lu?7o9zYXM7drle7^yb2YE4RR>7g0iD-{xvd}8n zv5|%|x{Fk0DyZvt+z25oLGkHe23cVLCaDnY7L` z(Ce0>xWIV{hHV0z031nN|HNI=#u#I~Wzg3fV{^|$^LiK0y(|Z=k+z20g;2H#*vCuM z5-h9k391@RT(7(jFlyQ1y|AZ6dhMw6uWG$IljmtViYPW-4_1dlB!s?~C18x2TSIKw zbKF`WtXY7_~i36%#qX4WkPgUfCi zagamtoKk;MD;s%PF$E4WAQ>|2QHL9bP1ES)yzlD1o4cWlL>a=h)_u|JUCydY_nrFU z&XE|oB_9cpXsmUTiOPfvYdYo|ihjLDeU$7g8eNs|t$RQ(cQO%NSEr;jOj|#H(Aw<- zPrnAU9TN@hr+?%Qg29k4A`Fz;=jWFNDdMPHMo}Up`H}nQhacs-thTuB2=S3{2|pXC zQ6PK2Pa2=DT*;haHb3s*vgbl@`RyRiQ*cJS$B82*zU5?)#; zlLV2G1b$jZ{!V(F7FdRy+>=+Ik|#!M!fnWPm|~k@xMJWV0Kun8?HmP%AQa_f zvymos5kK^v+%`RY2>uQ)#A*r-Lrmiwh+(o}_4yTo3FL$@W$ji!WxQ-6f{C02>O z>V0lwg~u-2d*D7wApwCtiW=Ia_e9Xls-|h7ICJmS`#bhdY>4UIj=u1VvvJ<) zxM|91tP>sp&T&7xjw|4opJPD3*7+Yi#q~6| z%?W4(FSE-<98*n8i4Y}EVy@6h`oxR=OcUOL+EDDIL6Foygf9O}QL_T$D6 z$%o244CETf1To73yu4O$@7_DwTlc<(n* zYzPn6od~N5^D_Bef{(^R+$lH=F^w~b!6*NW-iLc1hK1j@+NP~ucI1@g6x@RuMGT=` zuiZ%W-fb-5VVC340~B!UqHydgN-eSXNgAG;Y8pIQyJV^UnN-Py%Vs% z-c!HLMYYv8>N~Q0>3t-1)$&8G$If?0NZdVcO?f7tx#zxiFNEQWX?}T){ldWd6bCpV$w1nBZRxT9os-|QAUZ6lI3&<>-A5`Q`z*a zDwhU1(0Y!TM_TSd3%A*0%uO#gC#vD2*yLh6-%_61S>VyFnTCUk6|dC!=D1Br$a3BG zvOsJ#+UAGv;tafiWK6|8%{7Cg>=%LSqan!e8g*6VW@+94U#sZel{Y$eRg9pJgR)uL z_U>h*wX5Ih9Vj4Po%**km*kVo5@oVwE&Xx0@C5P5)|Y?Se3xgjyv|D#Ah96FnP-Ii zZa-d8W_+`RcXa-=rMQ0MwsqMk?yR5*wif3Sx#7e~1w&r`9af))+}hk0931XDQA7li zs}yn^%D$BAvfAW|jo4_BbI}tXWjM#cVbk{;pAgYqsC4|{LYCe_Idw$q`P{T zah|flC;$9W!FLpQk;}-_6~kK?!ORtnyvHahki zctm>xuA9AZXTP|c>sg5qdj@aXu#7eLu~s50_9dj;t2DUqS$?}Ev^H2?!L7##HiVC@ zc*C`UeLaB|_p-h?AuQNBYZ^B72J(`zg(EPds2Iy!i(s>7TdW(Jr`6E}B2`{NfrxmI zy65Iz=U%MX_>knM-rXHxoO^+RHJ+Th)rT6k1~r*z5I;B=%*o1P{4Q`W;b|~hE}HRz z9}h3p#@r>a_h~d+ZdY3!GmM_CVA{M~$<9Dh=fN<{EW!RZIW?<0sz zC|<2L;qxV1L8wnZgM$?gd^s9Y?=Bx(W`pj#2Il> zJVPN%al2aE`JO8(%7;K8&=d=PV{!!W=Qd~QZEk3sd1qK?DVYwA# zc~to}%)Yc%n}2Q@Z#=#TX1kxNy9RmE0a8{O#(fV_e`aCv9cU!v)h-`zwa~&=0v#1(on`)~dYN zdk;^$cRB2arGDC0{NcRL6{s3Zm)M%4*;?m2!6k;IzBPO;Bi_AR&v00Z5AmYKBdlj8`#t*fq#)HG#_*Sd(*wdYe4DFB)e|EI zn&>2Cf|^yqNqvK(FLy4xe@RARtD57Y|6Kn2EOXoTUV;4^c2@ZmS585Q>a^)=dVNLw2aX;JM7(q=dhIf1bZk(&M`Q4h20UCBuFCb zkRN#FueBl!>#jBq^6>}U!3tl>tDf&tz9Tg){H!j~SoNB%*`5{HoV|vO>{SPpE?Iec zp}rLAVyvo_)o|XSSdOPHnX(>S%2#?NX_q*2Y3n9E=R&XG1TEJTwBk~utkb2+RBqK2 zTCf&0DjnUFP&7@Ys3%_4^M5ho#x2`yMC=Az>p_ZWr&}kPAj{D|--}@<%p`4X_P+Ut z{cR*gU0iO`_llz!*B57n6wNtlh8`Ea&5%dZYl7cJZUgeP&>8Le^h2cKxnH0LA_cW= zzmvlj{7TodkHKDh2a{nne&y;l$wY7mjg7E3NYMrwaaenC^6`SoxuM|GbZ;5%_1Qgc zif5=_DQ;J5dw+6P9KCA_`(UY$&-@5@r+Dv}HfGvAoxV`zToNJyPg)u12NIADC5?D9 zYTDnWwU+dpGA~V%c1EI%U1J(OtLE;R)%!0`FAbe( zy8=+qC<#{(*^7|7Tk)~?yID84Tn_`4c?i{0bWb6Pt7&^{yET2TGPgl*+da{(!=K00 zL0>r2lMTL`(Ck+0!aK~B^xi(Z%SB2*Mhc3S(X?5?5rQt1;V*x*yFPi=LyIRrSkiHhEd@>m>0EDn(*1qg9A`R!55L2Jtz zqc1K44tU97xc#8ontSD#orXZPF(Rqj{ z1mCP*fed?p=skb@zf{#i-()cnVjxf0XGf(W|I2_kCH8>{hG0gB^th!&+fJm{AewIt z|4mL4hH(<>YXp6BboHTh9@@TcYRb^{8!SS%t+cYB_l&(8A-&ThJs9|qe57<#H1Xo7 z3D7ZYdnb;c9lf?Clls!TDCd55x19oH;HCYI zu26q@b)*IhS&Gl+ElIimWx)H;iVVtfE)MT#$duzLRowo-i>1&hlNo z_Ykr{PA(o}eVBJGyQ+s~*F_MpO~#}xlJS{B9znb$V6nb8mYfefLUvn)34Rok3nKxJ z#`%ToAH{c^ruY9@ZS7n-J!7ZyR<`1zx}}_3D#@zcPCdFn@v`Z$GG!sA2}w(37$_Gk zZ`;h3m`VoKn6ury-IvwsPyBnNsVXbWMBzr6&xH}T6s)1yd=D3Md6Q*9Z&^V1PsEVf*cWtD3{})QG3I@!8F9X492kP1YWAy{#!=JDFICJ@ zEfVvR)YSZ8VhJTY6#ZJQ7ukjwHmMaWKX_>CXw58PzYrtG!+F^I=zKgFU<1#~1Krcy z83{4)vTeslBkCz^HAxN4UcvxFNUwT)ri8XOsqFe=Oiouvd>HfWgQRAmZ>Fx!h1P50 z5%|dE+Gj&A&^IB1J~4(1A|gy@I{C#;w|Bbpjsk7IN*@&Z*m}3v9*-wY@X;L@PVRY_ z?=>SdvP6>2z+&gkb!kUT$tDyslOd5g~`r1j)M^!tr_`ZbTok}z{8uNfm zb$U*<=V+7T?ruu-X9(c#W(pH6Q9R>)>BXIMHr*$yEjNAd-r(;M?vvt3Y_?;$gwO7S zK=#jPh#~GOc2;iVPJknn73xzax8mO2k~O|J<{M7--XzFV9E=ewXhOUkHMu{u6a z+Ts6n-(Q2<%hWp*QyL7tdD45`drpe$;qR>x+krKCc#78KPAeNG- z0jwM!uN@O_J#bfr9kaPW<;Zxb48I%{JGYVd|y#gXIs|Ex~x=(bNu9ht4VOPA>CA zKs|TZxm+_&>1uhxFA$Dy(|ct*QC>0PrxP@Xi!%Z{=CKcH_7mNN`^|lGq}m;np|-xK zzovsXxa>H?Q&+Qh&;>i~{B;kvHjczW`|;^wWeXo>zZFiS-6vM0+zwusL|3{}?B+%; zx!RHTy%x+zDYv?{OKs{L=+9IMz*`A~yx}_52^?$+F+OZDyGzJ(MU;RcYvqddsCrF- zSy}!iuPlEooxOuJy(fN8)M$C7Hf~kDonF(UJ9Wn4)}>3^%%qmpK&`$+hRmw8uv79< z`|M!AXt^;<%duw`XSaiLYV)tEx+H_Nx#hnV4mg@ycF{;17q>pj*r<0~3Q{)+UK4<; zoy#R1miqy_dSByJNWaTG_XuJsiHd@bg9q(YcOP*V&Hho{=6PQStWoP1lbuv~6yybJ zB1}-(7Yqt7gwTYbmAySGl^rKCbTyo`dMYsvD;>Ruj~2U(HjOJSJdLr!9i@vEDfn1H zH$Z6hNQ9j4sg)As1Z6;N5V@b+NTm^YJ9pq*X=QqBW?7M0%>U@g>D7^evYYibPF%Ad zC7wbflsz#R1JB?_x+%%x})|iI?SGtT~>cd@9rG#Dp7en3z%}*yu`x0t* zFN?J&w>P8o?Sdr1!?UN8HO{{Uo&Rx*uD2o~?H7x{%6&W`}*a*^mug-P0DFN7a-4h(k^4>#%JDy|H zj(SlD9e=CG1@6VHoA#mt>GpS#`%_TTdrwAWSUPK${M36A%L}#sVBE8AzVXrwHOregHPv8CD|$M59hre)IWT2f4Vx_aE6Zs zaKkm9t1$?6Y3{NArqteGz3GZY_#8x2-4xwQKr&VE)H~)HV32}qEzR;hIQ~4*_W0%b z>bLpU#H~4R1wt&h5Nga~9++j}PY1vDu9mjMtNMOlN$tH~)8EOkRDCHB8@5~b z2d9qqiABE0Dr~G@+g7#|_8Y2XQAnvDUfFR-pvAWj-&bE$P;Ill_p6F~A=e50YcDRW zvP{Z|r2s8q)jMd~PDGZPXVKjPH1I-7(XKj|v8Lk=Bscx3cj{-9QcC_$e}t}nH2FJ> zm>*$0_nrZDv~&$Q>KpC+)|G3q0osUnQpQprZ!Tn<_uYEG=H+J%iT?H#gXrpbZ&k2S z>4r>H0M@71{#8aSWH?Oi{bV~VV)+dJ_Z`gouA4dd8etBb#MMcBN(1wZ0bf{ukr>n7 zgtyGckYljvJrddyyr4G>^xpUyp>%%p*q#JeL|sB@e|S#HqW=Bk7i~Dh#{#&*H6N=n z2zF`iW&ch6J%jb8B=;0{()A#t=#Hv>YV29PtBHa62kLvTy*ErekwVlvr=&hA=!;+F z12CAZ{9M~I=bgH+L}&N1}8to;e^t=_Tfd*k>w&rvISC;KW*beI0W)xWxes*b?aCQ@}4 zOX(%kA`i4geCe!+4Vpwprf0 zidq%KBYITdpY=2VBgu)i#5^MEa@R>$Cndj9)j@ub!tS`j0Mag5tvXpOIc=$pq~58Y zr<6sBRdVzT!lTJw)6gsvJ_S4M_4Twhr8cbjiymmP0c4krln~vZ;!HIu&L7_c8}stL zhD3ia-W&A}bwstEeY#l>H96~>U-GH%aS3jsi(fFZ-Cw zYX<|wOTaS$<)`lC(z7(X{aHK+GB@|`R3rm5(oG!`>UH{*olBCr$jCi%thICJT%T|J zR}7FUh`8Pqm+M}@arh{U4XDPKlVyuWtjyF-JuQ}JoML&zRwVtwaoa2C!d5^7bXsTG z-v>Hy+N!gZof$2FOx3S-a~OEewGDO$_20Q;w5FX7;Oc(DPPp@JY#+Lxkm?>*|KR~-UBk)fY}bVs$Z6YPQX{YTH2D z>nArI*k_oIQkitYE=zyQOOy6^+fBV|nTP~81J(mZLlj|<;F#ub(>uC&9!uA}tEMOZ z%w!j0+q*v7&;<>R+~|- zdX&89M_^pBN((=V?etD0H$_)(yDXzG=}ip64czHec}@yQ>pJ8O7i<&W{uc+bN%h$9 z0_$!Fdhpb9dRH$ttH=FZI;N z5U(}f6xV|pxr25eL#W2R?BL_GhzX9`8S5{~+sjUro8CuUuM4F_)<=S8w7R|D6AAt; z6W4h5F`a?_Q6o!j#*y;4_;o+`s_CV7eQvb9)7?Mp{_Y^2jFrmswZakkld+mkCBmnLmGufXNQy=wT7;KqQpFsctD0LG$w*i{JpwkWNnp{~ojt78a$ z+HFbx7`R4gf+rJ6+beZa zhiX4<-+1+C;S*{6=AHudqRLlw|G=-x4mYO(mTOzd`&sx~r>C1XyH2RGr1}!WWUT8M?|tlvH!XwMRI-9`-XE$+3ya_L~BsO%$r4r3fN{HL-fIkq{;}d zWSWeRx)NHs9YFT{Egv-_+Z5zHuH*YsEO|J-$5mv#6kSHu^T9B{dKR#-Boe6jo95-b zmp@t@{K@a|JR3UuwD?W}O5OZeo&0smF+j7Mx5c@-DGOol_dM+oWihZ5X7ZwvEGLjPtNgB1s@ z4jj<4X#E61Rx80}UkX8OyYY@+o;L8|S#-bg;Vios>mC=s{gJ5ris@DV_L`q-16=ke zQi{);jNt;*;o2hi<}Tfi`uQ~quEIA;es!F0>F`P!cz@#-J>_IGPE(}o4dfn{J(-o} z4`IIVr!?PEyoj*iLkKN(HbEf*A*8{`PzzL@11QT}dmHeULJa>zz-^#l-AUfIx#2(> zge2#7++Hp-*bq$ZYc@7BX*70of81MXx9Xl5@AK}p?$TK=PRBn0=2PRos=HF3y3QT9 z9695=bFXAPSy=YXz2>C@aSyZKo4EVhNxH#f`yvFULTVY|M8As4} z5X?c>hb1I6>>VRFjW?TIS3r*&t$aFQzomhGp@j|F{GoR%?78;TaKvN`;qRc1=iZN7 z{@#f;#8j%^zCk}y8i#E=pI&-;vXiMMh!lAAaJ=^U?D-|(Zl2T0;IR!DkMETBO^~#( zL+?&y|K6(rcS<>7aoO(y`;ll==j`t3`wGc+T@ma!dymJak4Bl2^+ip4tovd5x(a5= z^}Yznhw{s5ag|bPnk*--wNxyypB545jR<_-p9&YVV9eq zYvmnf400_Ija)SJiZ1bdXThQO90M0BOz{GzPKR%9+b-Nctg#aNJY;*FQcmxZUc0O| z4;JEhn9_de{b#=$exufXmP0VUF0TJ+<*BqDJC!|P>%-&M|M59YDcHH65V>wfw(;Lf zpWd^11_}|Y^OsLxy7W$$V#jMU2maY}*1nDa&ZzUZIqX{Ps`FcllY(#lUF^Ptp3F3} z=#c{pWBGN<|8^Gb1+gz-`51mRGAG1s{kc8fw%6Ip!$f<~x}0@rVFqnJV($Z^-W1w! z!~|1#*Rt;2Mx4DSMM?FwAehEU$=Lq zw=HzKTU+0qaF*UD`p5ASL!0|)BVlpbFJL56oyTGm=^7GMOjYDG>*PX2F9+!uV_zS> zn*CY4dlAe*{Bsc!Caa-fY8&s>%qwJ9*3A5#zMwVTiOWu5y&yf zM zH!Yv+FKFaKA~QIrOknqeK(5qx$)aFau1jo~N6fSIc}P(|BWmoZYTF{@yL@qcBAbF} zUnu^Ib^Ei6tKIIXK=|-)06*w_LF;Z@r5@q$?%|ZN1H|)nQx?B6bF-1y-TQ1LV)0w> z;6m@9k|$9mm1*cKS0#X+$X02LlOAJFO=%PSey~Y?r-n?D`r4O{ht`>{I6R;v@v}a| zpYCis>h!)ZecE+jCtgM(xSL{ocSqaH-uj7N+^|mq>&_kv0xUX^<3roBqE=j)f_=wz zbkmb-e;DVIJ38TKWYrM&rq^WSdFE3NJhIQAp zy0>P@-6?9xZF&EB8o5`OdRL0-T)^pjLn``hritU)O@M9OHuS!d=COBxL|gv+H}6Tv zFX-XSvR64q2?PYOmRs=Ef}N}Vt5 z{$Eh{UN?l9YnWmbC&TS7C;ZRe$JgR|NQpFZ;Jenk`=qaZRpdF?c$sg==;?_mhkYOE z{^6G`c6eE!S~`0GzQ*k5A?_sK*V>(RXwiqyNhZ#7Q-)jpTgCtMN5Ap`IB0CRYwqh% ze5H}8R=n9@@nyZ|p?8B$H0{xGzoEMJzC$zw{Ow}ewc4e+QSuqi#$F$Ayrva}A$WC9)QE?Xs2=q{9uW`B3{}vz4{x&#Ew&Iz&5kSY`Zn_zN z7}zqJ6t9|Q5nIs{vZQ&b>}8tQUk$sN6y7k~!7zvwzwsC}WbM$i9)<~Nu5Py*MHq`F zqiQ=EJAXj)7LyHN{PnP=cEr9g=?%dQ91gx>o!$}O607J{{d(8MjDy+UJ98~+dk6E2 zI{&o$-i+Rn)!b zl#Ar9(q87n32DbJr42s%YCle}zy7+9j4+jk1X}drbCRj^+(m{Xc2n`qPkBG8>v;x^ z4R_7;N*I4c&nyt`F^-B2mp9P6y3raT1PjDe^rzleZOTpGSWNpvB^zB!$y1#p&sOg+ z)HdzQb+&6Ho-9moV#_T&y$3lAU_bBsMQal!l~}_)=U{{91rLb`EQg2gG&6eGh!4$}OPL z(lYO;Alq0uOmV`rJ9y8BAIA_kU(QOWhmrJG;n$*jaTNpS!|&t?*W52|i?eLMA3zmSft*v9$jfGM)Ib%SbJ+3G*xoZuvR%n2l_l>?XD?0itM`D>$|c4T;KL7&%!&|R zK8Tu;9fwn|ti*B}^Vtu@uliRz`mD2eG^Pc6)55>`TVa31G2J~uRF{(zV=rch({FcZ z#3A!~Xax8%)m@5aF{zK&qF?( zkfqw8^T{_j5%8t&ja2m8N<)Gxd<+@$w(NMrAuA|txb%M6a)@0`N6UvpRbRcNe(=po zBjqg+^y6YlOclP=;S}pI;VthU6}_t8c{FBxvGF~lq?2n=+clW4>YP06wsS8*9eI>Q^;2MiAyM??=AYj295x#@>u@wh)~2e`CG4j^B^|F>Xy znIgnp%XUL}Q1YFWvZ->kOW*}EIopF&pLo^D$yfcCLi? zTKE0rKJ@Rp~WSmU9%Zla>U(NuJ zi(u}((2F2w)73n3zcY`vmeQ&Htwi=Vb-r{iNqB6*T0Ba9jV(6>b4zlc31r%EF2isy zrF`bDxoU+~cIQpHp1gFv1P(VPZti_rMj4f z!SSc}eGNNhKW3a*$rs)jXiDDL^29y4U@_v*fx?(9o=)$FIGGgLHm7z! znw+9_(75rJ=&m_3_;>X&K3upUs>9*2_f7A4Py!=eJT<7H%xB2GPlMUz7i50%>8QDA zY*s9rE{TuEiwu`e_tm+~_-S44axoV1pn$K(}(S0oVRqnc{Rz5-bXA*uJa^fM5PG?#Gu zpQ5-Tz9Xo=h}?-dUHAr!IC4E*#8^+%qa;rgMK&!WKcd=S8!yA!s&I;$Kxa|e^7K;L zgCiy>*&hQoUEd6Jxoz8V;l8HI(YssvfiRJ6zY*~@X2;>ct>e8UxYoiBHe7l=u0lfL zZM_{_IH=*M*To_W3?4c3H|X5eJ7n?;9{(wSbWDhA<{Ia#7|_bu9kjVesMj4x7$XZ4 zPw$h@Op0u8B|5%Kg40uUue~2%Lc92A>B{PS51|g*jVD)yQ`AF_sQe5;^Qw;Yei8d{ z-;=@Y<=0upsndH$ucPw;*URr#6TztQXCBlyD8!*?qzmHjyH@d6bs0k`vJ$-Jpoe+xy+w{J>wemU6f**VL8 z7bIoyjz%VY57~7pmqHBa?v;^v=8F*t0xf`(RGjg^l25;ux861-iP$()*!dPsB#114 z{G?gPkqCOBmw9<5@4X&d#8^l7i3cB|{i{xXYVp%(|4P5oKlrEN|M~y?SNf^>TmCfS zAN&t4=-xN!eT>J-&HP>B9ap}=Uc7JGabJ9wdU(g)^4@Y0$Nzsh;{Mmy!~Gv;{N~E? z%1hrzDW|8#*jrAQeq*aV--}CYx!~&7qRTgb;hbxJCBUOpeO$?rUiup^o7KOxl1I}Z z-CCDT@vqowip*kpWk9mVl~|6wl;78Q{Kk1U*mOUtt3UnIE{(}DIAHZq&PP378S9(Y zk33zu`RO<7n>m*6zjSkX@BIB=zkolVE$`{R^AV|_-5ZPeSV7B2%BqN+=iGX#%1{`) zOztexjmyZ{LPWMgb=)Z#dar8qp;z^qlCGDF27cdB@cVK;rOQc;m6%__2rK<^VB9Sn z|IUhYF>R$ti&LBv(w5GQFap6>gRg+O7QoS;_J5Sy!^fq%>_sGpBM<&8_QrWTv^2hW zYRo*!Tn+!EnGAM z?wd2X-~8C#9`{WQ1@qQB?q2x~M5TGmHCcG+mOH}j2P)eD z&J2^(y=W#!LlAuPxFLJt?f}a6NrXptlzVkQ5yah0u4mgtZttFQAJ)yhS`*XuhhjTD z%xaHTa0h19m1%}(-+fx3F8Z#H?kFUES8ebs8gI*O#H1o8_r_C1Xu?6;DVwpXNn+&#RIDD+LpfJ4u%QvVlg zlkg@zXS)x9%CGW>16NEa)-bd--VWv7E#Kv)Th@rWxKOn)!z9P@kQC~Vz z5+$L=R7>!-6EYp{Pr<|Dw)Cz=}tYKRg&9bfh{KJgbN#08!QP8eg+Tk{?zKuH4FL z_}e!S6d{mO-u9nm3KIu3>Vbfp?!Wm)?mgNpIcUSN3KpvDUAzBEmz!IVj|I z_E?2PW6c1pw1{tq7)o+h2}6wFCPZbZ%^v>{l;V9g{Iqz5dYX82-K3e-_&|DJ3}RnM z+8gu>Tozx78TE`}>faSQ-Fu{*YsmIkY!<|p8u|Ne1^K1ztt1brh8%!>NHp1eReL1( zFI7rCpTb@RExohdj}9^GdT71+yFyvR(8hRghCRJkz7O-)H9knGa~`f9-}?+WjvGq-86{aJG`I_hn6iJA-Wc_!DSwA2siclR zox1us;7s45LdcU0SMNb8L#dw(Gg)a6-xA%p=0@YOD@nGRiB>S{Aw4{|Vm#KyxHQeN zGwYLYlH!k zdb75B%sn*L41h}2W}cnR>!&vgsQO$&@IUMMeh2YTkbt97Kk)#QxGF4mnE$H-I61<> ze|nn+6ze%tMf&vGV|B`Go?-2Y@pHqN0J;!(48*E|+6tx+!>C#jU!nBM@21F%aDGBM zrX3yZZ7BZ%j0rA z-u2S286T%ue&0BMgYFw#y7|6vG;yyy5+rJbveHymiOL~>#wz!KIMEwKED$6 zaOq|@#$J5-&A4R(hx(Ayc~J$N(?ETpMA=GiTe4{T_0!su3TvNn?(>0KXo$-W#65@ zE62)9<+}kApOb@pmtpKJ-~alZh!|F0pCaV~dPRRcaISp%eaT9hY(!&nr@P1cz)9LE z#*ap)FK}loFaJM&#O7n|j76W(8J8nit2Ii2M$kMn0+|Ca;AZPLkn%18VE0NMOq6uv)af^Oy zwR_=a_@gqSeDBjj-VBq!0J`S(xcch=wNRq|elp6p#=XLQEcjVh5g8M{DEu_GTc0Dz z+E^p|y)0GYd#%WW-)7%0JXWuYOgF*fzhs3Z)9_Vo)YHI=Q_0cv_B%p$f9RdxwwZup zJ>%Q!$s1V@~jzsQTiaT)V zxmD_8Z4utm-;Bv|(SDQ%9M|STS;NrQcsEpguY4aj9rNzp1FC9A-ds-=2zueAQ3xAd&3k+xC!#1>6MtTxGoz9X7YbU zYX#$bQx0jEgj)=h{Tf!n^X)VhUiJ`B%eOO)LPEQEsQm-(4ao&g2(IJ+9t%hZlE5{1}|J z5^K>%_6xUlU04^~D7EeB$=w@5s@ef;uhq3&FqW(m5zHy#fMP=UY2&$dsSDgOvfaSF zNAAbmMI=?F_ydOX4Kr``b(0>$15EE`Xe?B1W#+{@gw+u?_n94=^Dwecq) zOLH&=IRXK;uL;v*Ptxa)nUI&DUQ%*I%urU!4VnewY#d^oNV zQOYe3WjGs3qPxIp?VogaMhl4TZ$AR#Lp+N@r!JDG-D{IvC}u#SwmbbZPVJat9qZd`FePKp*#w4 zlzbc7_AKyf?HAo0v?%L(>>SNajP=!dmp%@AgMV|m5?uAXnQ$Y@V9T`+r^InP*90U- zk7n*8*j1okI_?AyI7P`Wp{*^$8N!4m@o(sE<=mEei-JMsZeVYH@S;_Ea*}oRoeKJB zevau%CUF%W6<1eYIZx9O*Z#P+n)P?ij#bT%2gq4}IIXM7rj7oT$=h{)tseM@+6l1Nr}oD+iz^LXpz%rxqvk9GW>nYm=#dU+}>XO^gzC* zh=Q4M?}2Dm7`osV>kbKhUn0P;2L~OLI><}4Yv_jyV=2MAOF0XKO@!zMv?a311;8>J z#9svlSu&nRl%GbLYY(mQ?eX_Tb}=E2Tk`@c-B0Vo6NbNf2SfzQ-U%!lPm%22;l1z9 zjoqFNw!OH=C?gBj!s1nj}GE3WN*d48u(a+P?$2}or&!6DqR>-SXE&BX+$ zH*Lj6tKD|WQFoH&NLDU+WDLqH${C4p`VdZPe@W)Jmu4j1Id;xkSv%+adWLJk%W~b8 zzNhsu4OKo03Df`SY?PPJgJzk-K#H@dHux|a2Ia`EI1bCz{&)ay&9(w7{RWD=q3vBz zp?&Sg8}@xce`=^E-=~}`p6tF(-K*}sxX-)8OV6(F=FYhpEq5kw=boI1;(G$i8Z6~i z8P{#+hf0(KJ1(mz+Yj#EE>f=>xYveyyQ_>Oi+SnYc+uJ5u8Cx%h?4j%M!bnCoa}8V zNXRj2CWzAdu&3jm_yHOL@aKq0;vrnpU zY4OKa^bSt-9^c#g%>~6Q@@4N(;*6f#ZaHy%z7ai%apVCiV!{~b2#-S%0y#N}3$+ek zyP@|JSLj`^3&x|1X75!rv%JE53o17ME3j=<89p4-_Y#cQ~(1LPxz`Yy{f} zk=K(LSGK*Ru-QASf$=6J>evw3W*NN$p{1T1PCI?;*gwh4F5z)W3)defuqC|3q27Z= zR$oxwGh@a40cEPOiS4?`h zD>S@nH$nDIw9{hSJb3VkNu~Eyny28q_8#J)cQ`BB7e}wZW|5K~{2ssGd#(HQpR5eR~p%3W&xvI(Iq zA1v1`75@0)#=&>>4b;0NGV#7UC}zp;()+>b`%u=&R3~23ZwkRR+Z3_HpyA-lFfVP*W06as_)$d7#X99zW|2F17_RLFV*(uqi?&8C=tKi zuaCWNyTIwnSvX6C`hBBhYard1TVcLfi3NO6yXu|5OC>Hk=wwhVF;VG7KSOin3L(VP z+*3`?*$kUMWI6)`8~hI*8^>L#P009N(h;i>gq+$~>Vpa|LK|F)y3A;!@(1tTghgZ9 zkRH3k*puNc6WBI=<*5E%G_p;h)$>`8N@5?YHVIN%7XcC|_f^Z1+EL&=A-_Gjy#Yt> zabVqS@Lm-(qysONyMi7zAru|ZAA%4B7k~x5hpnH_k{qy-=FAu8{j(9}GHJ<-0+=X@ zEQbu3{sdmy)r`BU!f~oVosPVxkeG1fRZ5_z*5X|ib2H^fX|_Z*i*{C7&e+6>OQe+1 zQ%{T|9zkuk0NMB&BRCx-IxB$fBURl1I zTqefb*O?V@j!tKy8`4CF>i~4?@fT-3fqm-A5B7lHOe90GO5$m%`?wt^d(-Ha-_L8+ z-mJd!un~5x_@6E{u(E*$1{Ogxcp!fzldr%zVUAjXvZ>r(s^zUFF3j)vV7YFpaB1;j zTl5aeuHNh1)@LR?6tl=bP`a7_I+SH6F4K+Z7UMG8K#dvmmk}@?tq4Ibr?{wf^zys( ze&qslar>a~H(j*7pG2cYJoUtoEqiUAvew)!pofcFrjhmIX%_9tHUoudQWuFS7zyYyoT zEYY&dZ$~5+p4ooGR~$;yLhc&FAf!a#1~65jFI&JN-9f-jO5Rj%6()IebL#ThrPbQ= z?KkvPn{z2L-r0tCZ*pDs$$qC2pGidBr|vsp=^o=AoslEgpmH)A!!hUI@LJ8dqv4Jy zW@wo}p`t1<@j`;nPrXn1O#8ib?j{$x2lD97kE<7O$pTD^k5kB6)-OlJx8d-X#$e|Z za^D-@@oti${t*^3`}UBqT{n1^@(oMre2f}&|2q6>6~OMj}+hTpP=k9@B@y zG({aA2`o-#+r3{)hbMVn5YPkfCizV#@8RngeYQ~Um|GqUTst~3SvD~!#o4Om^Wn0P z(O_p74^xAEX{=F1#fVN2KvrGQkmGRD?1cMPl9(xxV5!FuiCF5|d2zCKrlVh|^SFIQ zyJ@{_P_7cemy4gOIq2?3KDl6AuS!#HsoCRkanq_Zbg=1hHeB2?)NO-q{NuH)-YJ%cq+97gTaw=S(+ZI&U`dk-qmpHuj{A9 z3~W5P2taH*C8Si&zylWVU3M+8UGK)Jwf%f}eR9r~;Fok}ZM4V( z2W>UK!Spt{(KK*GVPh?;s|uDlf|JlMjEr_=+L?Qc=9Zy1yKBKag#lc|&bV};#N}H4 z#N5!pe0fa4_TlgaZr^T2J_oBz>s_F-; zj3g7l-fy5g%l#dQ*hrDyr=|FGfU>!R=HPGl|1AnQ5-SW5WhMm;(E=&W-9OOr+a_7N80Os>-+ZR*8AgzbzmQTI#~6t5+S!Wa!sjCV+`jEZJsZo)EI3JWZS1x zlS7XKlK`~p;G+bW?O#X5@#GkFFBv+u(&7_8R+GZF`RsUlIjzgSiMU$1X`eCa|H`IJffRm0$oD zvDey>p!DT6Y<}dt?|OJl!S-3VJg19m8rHEX-J<2oX^bBPL}?oXy}iTh z6JXB-xKreKXso>!*&*wy`8$}S$vfeVl@=o~qkg@f6=YOeo$t!w23-c4(Lq2`Zo?=C z{p~X7@>yYgr-K3p_7h&4z18(bRNoc%mXsFms9Jx4vae&BR(`O%W%IbV7hw^*|%X`==jjf%sW>pDuCmipQ~J7du(k zZ>Met;s<~K6s(tP8f@SFZnp*=N4KE!lP}kU7XmKo!+o;nl3^O+=CQ8f2~Sm7xqIJN zx%nlJ`D*J@W7%VVJ*r{Jv~*a+qEFN4YeF}bm3CUCNtMIJAZF{N{s`4Lw4>__gZ%epQ7@E`_z5!?!CC1g_|xri?uol zFkTJ~FPxiq-(6>;TZiF)&DI&|v`lH{njJ#yoy4Q_KOC}hlq)vSIcUCqc)%0l`>4)W zOIGhYJzzk>HTQ!iuem2l9a^(u%(2w=s1^1)f)a`71pE4mk~5|p^bGuSoi_DOsT?Ve z)zg@(GWCwIyMg>vCpEpL^jmjNTAQ>XjzxUQ@dx0IPXJI)U(q|Eg+oa$&H=+`B?$@u>Sw z(X-LspzSXYoLgQw`fAR!SG1{;0yN`?TrOe264U;$=j64uf4G})IDV>(y;tN7bbV#= zVWR~BJM7-?sGy+N?~Tqo023tD!$Ke)IQKMp9iKh~G}>sL$MJcEvd)|N>8SDqt-MFv zSE^@(UFp7val1OM`BOpD=T^VRk^i>6E2SM5hfh*u_(`G=A2feBfYppgXtS%QdqRn0 zUmZ^VB7=;%m8sjgE{af?R<7O7xRP^76XLT)owH$BbH>&{ayxr{ zNRqqj(pia%$)+oBEsSGgEcperbagm-f@O@S_MaKy;IWuR;(YT|0okrMk+3g&_(=Di zdk@fQPjRlxw@x*Er8G0%v&^B+4jh1cSt2i!O(-F~|~J zdr$rP`DOeXUVhzJdZ80#amv;0%#SaU+mxj{r8yggd-w3QivZ1pFc17V=IuO0kyXm_ z(6s*+(;=yI^@yGP?vgne%U%I`+qP1UdpGlqyE_7jHQ$R~OxIeSHr^%Ze)=?U1iE+Y z`>2A(sbE?cD4m(*wqU%~UB#QNa`Rc^oKUE&s?d=3t*I-@r(61wAgaH~s)3j|#A z6nqXTR5<`y1Fo+)z>NmnFbi<%Ca(c4hPM7%g$&J**78KB)| za!xv>nKyMiE9GC`iZli1;1V%%BXfSR5~WcWw^`dvBb9Dew-*2G+?A!x@QIdyq!1$f|y$DC(RH=nie4!I!u)HaG8dM z2w^FA&!AO#;gnH2ksvgjqtsVs15j*yg3B@TO7oGugk$H}+sv#7Sotk>qcdQ3OK zC_ju7-NiS5dUTxibb&nyC59BhZb{85Tm%JF#{ECJhMc~s{&S!luoYjSrgrmgh; zeO}3SYquYfyzVAuVb@8{Gs4+Ur{91v%jeYZ+9#U~yt#M$XivRExjhaD#ZJaf-a7a0 zT%jSVbs6?+!7~>PID3D-S2i74>YmDQP`xRQHYqtPEgWcXHh@+^O7YE} zg1xVMC)AtjA;-}bsbEKU;gu&2?f2{xgdyp4Ncgak?^ob)I-039YaP{jUp`#4%xn&1 zBaVe?r^I#WjZXTY+3)c_PPZ#GR+l<8L4hn^kLaV!g zNP`U{!C;B40Fjj~t&T#0P!- zBMW?T;f*`5esd-(m$b8MI8^Vpq)O!YwT^MivGa)SQ2y&Ly$E`}N$>X463dyz-cuG~ zGKWn=d5c*;pC8cIegp3id8VLK*wwz{*mq?=VN%#Gx8HJL@LKq$&e=Xd7*sC#LlwtB zwNv6c^b}EEoci&85ZUSTq^&h-eyTDz2dMSXu_4NK+bhsV3s31S`(3?98mMX~8&f;I8r{q<3xT4%M(P;EU-IqH3}Aq@w!S4qMmUd&&YV>e8iZbfBF5bpih zkEmN3JNI`xg$sx@_*F1?&Gu*TGUQh{^)!#@RgtdrGWylKOr?|btqZW#S_@`k4@Yn~ zA=p~Cw}z2x{Mf28tz(;-pFIQKXk%?L?*`@i_01A*&C+eBINX5|>)mWRtwRuy#KlT# zgaUW2Rpsj1wbFYkieCM@w9aO*h@_GHIjWuY+ZLBPdSFnLBL=6=Tjf5DyPQ+t3F#h5 z9zOzKVa^nwqoCF40u=8QZh(Fy?rSnaULt#t6B!xZiR&4gVyy0)aVpdE)Zj+YH@>TP z{%h`vIuku`oUBk~DSP~!Y^^eT$ezGd`fd&J{@vf-2>%`ql=iK_=FmCZ4>R~MbPmd1 z(b0g~kuDyA#$}B}Ld)d8->n-P4TNM-8U zhe%#rwXBsL;KB4V!JS{z#;Do#P`+~MK%dPxJ2X&KWSTyvzl`@dcV;p|y}8${xyF4- zP)9)Njpf?7m+rm0%Y3~gngQ+zf%L)4uKJhfR3idXfHc3ks@GWsB-jmqaBN$-IKsWm zjX`g~DY;O<=(KS{^}x!!&B?|oW~M=Uh&QEmJAF4>9P>p^Wr0?lBv!Cm_<%YQyL zTD@~9p2j`YUx2!It-Eo7I1Uf6aNzj-whVj}?E#DOnTPxYEa9y}7kyvCSVYcSr_gh+ z^|f&j$%jgGaKdcDvVAl%z4*W(Rk$Vgu5#)!3f+j6ecQd;g%b*> zX-56s3FZOY2MnnB>#6vui)6Yrc&+UyoH5@D6=weWry63gd(k`d)X##@J=u^qzeJ!4 z5MY-XDj_)TJ-F{*bo=>EbdCEHLOSSm%70mUbpxfJe4NY{L`sJt_HVWT(#^^t?g1!|lH0S>gG_sn z?dLl&)FkC(zzxO*PZ6#{4arj{eWtXY{pkV8|`C z3T!w|cxxiTKD{`GAI~j>BjOnHjrBn~0o>s~yER#^vY(GkVM*72xaKJ_AfG9HjY-z_ zcByQzeNoAIfJI7o*Ge|i-NEYs48AdsxzyBEuM@{dGs50^A$xcI4#LL}?Bo&t+b^yH zDfuP0OSV7g_F%6A))30VirAFq*PX|Oe+T2(AGiJ}45G@!H>~%G7x2J1*Lyg!Z@bq^ zd0hMby41^+|GFD+Kb@$p=<{pLDnp*;esni`A08-nmVrn}Bc8ob(-!QDdmaXR2gI<} zz@7Q)8Emcg=D(NTs-Pd2|JVNur0ZUO3&QF1VPx*A?UATDfD6z^9qs=PD%d)S8 zHyaAcFE|#8a9on&0PW<-wWiCz;9f*G-G9HAy97Jm0ZtYCizp4YXzB_}SSP}ztty*= zB(`cLG|6H}wkZIgg@MxxI=t=>I9QO+>~~@Z5LE-1Du*`OrkYk0zv)_UuNqszp}KAy zn@=CUiOwKi{BkOIaKI+f|G8FcE`jem`nwQ zqEzYkHOTD^{vCnrk%$#{{zZ{%8r!-%xZqy%;rFZO> znb@|da<=@w4}hk&)Bm25475GDYsRz4*Z6}BSYQ16Fr9im-|IRl2y+ZJ`Q~~9VSaEv ze<|}r`ox$gl}ti7E4fwBZ!+oIck6Cj+h$R*z4Y&4-62?{}%w4J*5Nfry~Zect(AaHDMQX%t?{uGB8 z*z?eLP6TnMua86|zT@*PF@5&2`m6Z;BOuCb!}S}4;%#6rnIGR1;h3}H60M}9JOhu^ z6&{lzLA5=5*n}~}UWK6_{~%@Kmj;|9Z4O2NZK!OR%weV0Ekwva1XBG{-Anh4uR>8KQX?Rsi{Yv+UxEiJF?mgy%#g%bnrgRAuu)b z0&-!>cc`k}&_Nut6J2#l(i_9>1iik7(c_M`y4VfnIWYnco;nO}gAh`?dSypcOu=~W z-By{v@XV}$(7QN5K&x#*3+b$=H<;hsbU4}Q{gtsiEX^k!DdYQNIT2-(ffv(`Ip=X^ z3-{G!M8|DKsCjWd%j7aJqsYYu$OHA6(n*u!5V#0Xn*|yp=*3#74$jzFl(?ZdT~ z|5mG#%E>5uJIlk@>w^e#nP{5GVty!o>@ zM}C#2A!m{DA*>16Ksm0Q070?O=iXbWKgE{IcHkH8ILL-k99e?in)PQ@H_Dv~OdBtcU7i3{+l40gho!dVWr>km_V#`PaW&RG=*Sq~YUl3G&7DwWLjmdb)rK=A#wrar?UF9}(t$E)UvgBV)Kx(~4z!k39xsc9(<-qL^(& zu9pBtdu8%>hn}qv)%%2xKOxRx+GVO^-rBuyHkq)2Jg=N{wG-RDPtSoX_R-+>v0C4Y z@wtqG$Rc42YV$g+NrT}+s|kX4PExwX4NbL`%!s%_iu%(Yc~xumRv@(!fLjBe)hOIL z4UGUO;T8#1#U~1+ENNv-&RMl*Vf*Yb6We^0a zI-L2&ahyoc8)oIhU21bP7%jc)+8IuFxE*0n*6o=cak7ngr}vQP-!byjO)DVW`xroR z9np~lr8ebd#K^lWCwuNrZf+82JK5>TQIxAKpDI2CKAJr6BST-0f$ny;H?q?tkDoZS6X)20m{eBy|G-MpL^ z;;m&jO}oQ`=Aho;$lW_su11{yDyTtF*s`bw0!eyxQlP+aQ@iiNKJUB@K6-a;Jlb#2 zfD#d5;u-u_JjdUQuY0#wC)5MSl9q91xsyNKJQ^Lmb{5_Kb&D}UmsStvxx;Q0_YQfy zs*=Y|Fd=cEo0|#}fVE6;%dk0-UOZJ3-)-bX1bMNP~WWsc-_yyBEqu`yLrU)xK z^h6w(U}+e47e+;r-Ej6Utgxq-@gU!=)ZC@|rvk@UZ#i&}NJ-j;XR8Azz7iPn-5rCwAHt z&zvc5B#G@S^&YyOJm>!5+}F=|+lr>8Mx|@p@7(*nL%f4H*my0rqE~Nz;n=133~Hmie-&IoKwEmh+ZG^k8U;fC`_S(C zV#l@_7f> zw7Sf*KBoT65J|h57yoE_AYq&qTgMUmxc=C?q`FEgC!b?$P9GeEyHcPlsP6l=^MNBD zeJ>Zj-TM6spk5U@&V=zd$bdNR9gA~sH@WkB?>_16vF#gY>N(OKBhJ4H79gCF4qd(> z*~8U~cK9?c&E9!U_z0dG$V*(@F{D`({7LTyh`fh$d0jPtIbV$e&obJ}ZWNlG8P@tqMO#IcsmZR9y1uzqVc?Wp0?n&2g?>MtSz6mcsC z>Qyx+H>KuMJKZ?KU8CR`N_n;8yy2gxVei zFN8^)4!j)v4yw?c5fFcIM1-2t0PsKq!i*XTkFeQPrn?>darK+HPd#}Km3vATn}Tgs zX(e*!lTSy!I|WQpZYga)X<5bg_9KZ~as-}F7XI$obfh=a+sib!;ha3r95^2TwUcep zkac|fj6%K{7muHJTssSktS?to;RV+{l=sC656xrK$%i&miD+_koV|@ACwS|V3>Wn# zr(N>A$_uUh!|6!YjJRgWSzaGOpn;&L!%yp~Pc(`COT~Ru8sCn-Jer+;A>1w67a2(X z3+E00yy9SA^^Bdn5$}cU#&om8b3hx`8jifZXQ&O=uYw=yzUICrSqLKO)5&S??yuwa zAKGLt-riOG-Y{|7h$MFcBBJQIo)_QdUap=dI67X{YG=lsAot;fLoVq1WX5(zsN|9Z zkL$7Wb)-G~qwfON8}*zNiGk9U`LQ#L8^9hiu7=0ZF_CEt-r@|I)Oo;Uy+j)^HrzBV zSX`fBafmH2mjz1!4)~W=mmHW_i2VG#2950|K}(J_bB&0D>#kSN131L$dVfS|z3=P2_vpXfyFC1p zw4PM=_0amNcX(dsh0DfA>kOfi1tpENT97mc43vFv?-b%76AMJVVAZ=_xO%74mgGn8 z@W$b}wO8^v^$sQ!0y;80TJ_XBH8m^mqg;jowu)|EY1*6D~pjgRD%z*Uf|XW`9bLkF4>^3` z*%tcr=^OA-4vh49r^+72nf`zbP2szrptRd3c$|Fb1Ew)&9yx^j#x-l=Blqo{$mric z%vyJ6#zjx>TrSqz-lM%UOFbxa{I-jO+@bf#ddn2r*7ZZ)EDq36W+b6?y ziVdgJZ=CMk!`46evC%;ZSf^x=oSV9i2*+Tw(k>~nzi(<~I&H2v(yeocpuG?C@^g-3 zt~rpB5kTACCCInYV7J$#d{RB%ZxpXwl#4-O5Ep zN7MVs66=iP#>{iQW*92@ku=C){Z+xhpzK%o{$72$EJO@cdany_?-Sscy(C!=WIeX_ zIO-+3OgtelbTS;r$(P>a#Hn20`>@&w<3ARvHr6s&tyHfKKaur|D_`7qNSL?1A>BQs z5mTGmo@W>Slb$d3n#O$G`#b~no`MNST)o%d*mEd>t9QI4z;fN1|K7h$o4U>QxB2%& z<VfCgyNn49lhTWux5!m{WvoYI%%jyt$ewIVT|_fjCPdyplGk3m*B*Ttk>LU=sURg zGp}kqMtU*PTs6_QrM~lKxPr2rU*M*$t@nF&t-TLy4-+;1YH4(+eGvGgv~uFJa#1VO zX@ikD(rbqc2fv26rOY|BEy%Z#>|orKGaCxgZfyCirjiO*x8&Dw`V#bBd9r?G6AuD0 zu~c{;!}m__;hPMstzf=eF#z>DlPh|@OyMz&zrMSxIq54`>&P8YzeN1G`5O~I^%&aLKe|S`8cXW<>mU9V;-<)V-X4{P>a*>-(lw9$8(f=!5=lLD1e8^U}(@9CE1%0h^2fTK67bn+Ap5o}zr) zp?7}zWhiAm4&V^Sqt+mhBY)`qE&VroM>Oeg_0GzP3LTB!F}o}o4+PI;KWB(aI9N_2 ztrjHBfkD|X?p+}cSy+e|*z{f(p5EiMPf2nf2+kbp$mgwhm(kw#I9u2(#UY?|4wtjR?s;<0=gPq_=bX)2DM?-bxYWHSLA!qftv~0 zmO;V2Tuq5!Jpcj3zW9>EW$#7qcY*sw?tl143SOKD6-@R{Q0-;gx%XT4+i==hYY*35 z=-t-{lhb`M?kTajeN^SY!ANd$c>#lJ1irS@q_`mVC4wEi+n$`}ogLFWt4w6D@(*R4 zBs}H1=9>Rv*;G$NS#xBfq!*xiZ|r?gD{|x@5i0_Ad4~cR(VngDLQ~^Vw>@0V-XCVh zL87jIcyZzfi0A$&z{x~OEJB6oK3Mw+*HG`!*g+>dAPzz>%xx!w4C^gXzCQIxaQ4Bv zQ~pom%K~=g(8j$;l{`7b{-cow?fc2Kv%Bd0Ys*gos9(!8;-I_>`VGVvd9Ad@y<@5& z#775hlGL|h=;ru&r8se+fFVftWT!cBS#B$Bf@U2P*6_O$ zzOzvATRb`JJFPIi_U{g#W9VMIQ}mGof*hg3WX}!dU2QkP0CCvwFQ*A1YWcH_EJ+>L zKsReHS}7hyKF~#Iw|68pgm%>4qoO~lBC}UJJ@h_^{fOWO&qaZa=1=d!;hlfiExqR| z0T!kVR{vtvRDX+tznE}(*KRMp-}XMLcW@;?4E^S|u#uMa+@8aUO~ciaWQCA8xMU=A8-p6%w>Hzoo3RyH|*+j10u0cM$enCB^~ z+th;sRL30AhA*b6woaF={-H_IFUVAk5YF@te#mk55GlLYOANcR`}O9>XrrlrfL-zF z%318!C_HGF%1S)agJ1*3Xo~uE#ad%|eSzaUD@(Q#{|xW=1}Auj+zhlOQFtWCBQ8G0{W) z-8Aa9b_nIuWTM8NI%nfKY&KAVnSPP*OWP0{`7LRoz2$(@Mr*0J7I1rku$0?7>XZzo z{l!&FGB@FRnL{(nQR-2NI%`{uzzNTCb6p50;vD zMtZvd5?&_&iJSYOGmesE{lLYQzlgZhKW2baQ^O=t$RH?BBCy{c_{Z2Q_k4ca2G-JQ zIVF~HQcESvBv3Z7vw}yY78*^xtEbut=mu|=<=Tyy}K&#%%O=v zB3p2Wy(f3v0Lv^@kBAXfq&g4t6PZKv~%es6#HhXtA^dQr%d}27j?7$wXL{dI%AqwD#wgf+v_y(I!`CXX$ z_W1_ioF}dcdXmV2MqL~1AJ1wX)_p!B~?q?fb@ z_9436azF>NvK}MaZ0O^f@s=V>*&b4z_G-Wp?8SOKT$5v-+xrf^A6*>R{YHUnXd63% zJq*LnGhmc{RyvUq4g~)Jj^I|Rvv+<3L0%Rf+3K5(+9YzpAPTJedF-3`t2!3+66IW1LB#DkqLL~eMa@r2#q(@*4w95Ig6-h%K+6h0+#=&dyUzE0a2TFQJaOdPZj(zg`ol+XZ4n35M zGyf{apVTqs3kqv@TbIVUKD)h#U1(+Tcah`Cr7Itjv-EBZrlf1G<&a#H4eED-MA95k z%vTeBKul489=&=>&+D)45OYh;KRr`qd8;Ab5zuTB$baFNEXRa&B!YpaDn`aVsqbrl z>`$=asEY8m@sQ5zMDN(y8%pZy#p2pC<-A(;H-cZ_H$&uh z{8_q($o`gvN0y1}^%_;@D~2do_y6`&d&W}NlU@GhE0}s_vr2pAo|}P4xt{=kF^mqK zO&cGtGw%&8tp(z2rr$OK4KlNivr~H~?Afrp=F;@Z&_@Y4!6^WYjU#>B2m*lzSnoZw z)TwNMpZF(}`rmB1Y^wlSBTN5dWnD2|d)3(D%BhN-YHLT-t5bIH$sq8s@s85x&sBS& zWCIcZT@8PWW0y`O8U(7a;iT#5iRp>)sbXjaxoG&_g#ons{F1yYnuXRcuHgYGSmJU= zK0SU1`_T`=Y;>Q{uz})%#-l4o;Ae+iX)zNn6x@(tMQv<26qI5+EB+IR8In-i}(UNJ-&vb%Ws-8kQC z9kLPN71?OjlTe0rIm|7DJ$ntaoXxe!R~&HgHq{s|jw_x)OA~tzx4#4VV7?-=%I=Bt z#WO|nEqhHmSJPa+!xA$tKVO+{|mt#XJdbH|aPPc!QPA z?x_KK4v>J95Em+0P$`(E7h=AKo=c-keMoK4XSI&SA8mWV@NSwI4plA=9dXqA z0|GPo*0x){v(*5Th$f(RkB71soEOSj5U2gTk6aCD@7Zh4Y)gB?7Kij5bb3ksL+0}v zK4@{8b>5z0+QR=yNdI%OT?+oj5;NZgn_cxXtd#Zvh9*297m)xMwmzAz`qU2;Y#eI|J_NtH5caDQ?G>zvF(TBU{QrM5p%z1NARJ#PE+36NKd?XJh@&Yb9oJl?5Jt$W$WM^!lcD53ZMcfrsl`NVAPC5 z%b25gD(vFuGj1%($ItCy$?)R%DaNUs$@bf&Ht5@dpVwM^%TRh7(i^RD2Af0T=$++O z??WY>y(8)XGY}n>Up>B`L)nAx{syfc;(JrXP45S=v)9gSM|)$7hxDTf5A{>8SI(FE zGqrc!das55iOP&~y9spX7~NT7ByRkRR!%QtEtU3xQJ&M73ePYb<-I?W%TE`aS ztfR@X$xxinpONRW_7%G4FALs|CQw|vQ@Yx-1D}2k$Y6Xv?gGa^VMBE3X(y(*ZuAo1 ziD(&h+xai|N#XKt8~4>lBD_%9`%v$2$zk@Ko3rixkL2PgTi>x>3V!g>Rqq@-$b1%h zSU3eLSUqhpVYqvOa|T;@n1S{luS2Ozz5aTUxE6gJw~rreL^os0;2-J8rYKjfv#Xw) zU=Ck1(mjAn;>csE5Vo*c`F=DrRudmS3v?GGW__VVH;3_Rtvk6*&=L9Vy_~nmx8nMC zYe;}|HryXFqaGu>&W*l47_w$;Ku0ba`i;`pWcEk4+fv)~5%JAli{A~y6a#zb4EjM9 z^v-gt_n#Qw_Kv7Vj8POQA2qy-W)#{Ub0tg%-Si`IZm%juiM73`;C0G+73a4Kt_f_X z0yj*LXv@{(TUwM&PT5u)$2vRxyczNqTr%ag^ZsV4MjLuw#J!ksQR-8t=38+Eq;Xe> zo98ECI*87Hja2a1G}~H?s8W|MB$5~QDFM9@gE8;IIp`{o3L2a`VVfI&;uty*Ti)$F zCx+w5D;!x|=y|dMT2_kkaJ$^lu{lJOMD|{cswa@{b$rM+Q` zBfU&`e!hFn(eG8*rtX`*iCGIjXO7fGb9of}9ZPP$yV&ewFFZr6O8bgQ=ev?&-piQn zu^(@9yX`Azd8*u8?{wd4dKk990u`KxWc7;r+DS_Fe z{3{dWchFLz?VQ$Ry4rPFT9WLUnaRnd&0=Rv_>7-%H4Z{APNy_Qe-82@{-TIfA}a20 zo#``{&$inBt>OVpFwS1t;?il`W*hOoSNA&id3Q|z;-0(v=)PHZy`jiHo}ZTJ3szC< zUPAAm=o6k>hh+BcvX?5-ZA(Ni)wDN2Ctv1%v+w|BK$*XC#tSJ9J6>67Nb-+EM%e3u z82v#k6dB{)t)3GINNATOYCl3R>E>udnANIG+S zc1mGbe)SHHrF-^hwCuZJ4otZM0J(RhKRRlKm5jfYHxJgEIKWtmYI*12%MXa`$m~nJ z5z^}2qMO+%%IUoid>bS?>);cLbnk!kV0$QrrMZcv-?n)ND*>*+k9QT+am}EQq1@** zFh1gvsX->b`(tR^SEa3H1Jw%I!^4AII9?IZCvI*MfwJa0?s-Y9cS-X&AB{L8OcY}) zeHa~QkTiUq)cOzKq{s_&*kA!kxkEFbU%_qg()5ND6x?$38S*J?mYU9tHm2F^it=H` z`qo7!2|+8)b>orSdia>=jRcS17uS%`d|dB0GzGQ%?L9zvaa^k!>@7F$?CLf#PD;v^&>|m{ zARyRk>0d72ZFDsDLkW(pnjA=8KyHp^1aMHsD;4v;?0q5FE6aaZO_aj0+@oS1B9y%! z{ZaEinC)-Jrld~BPqUteNu}-H!JDtpZEQN;KGpMS=O}Rnc5>Ys^H01{)td3Qi0;g{ z*H(}0rqf7v_Hz3`eaNC4UzQzNdS4eA!S8F{|B~Gl1S`3YwL02u?~)&tdwSPkTV_mr zVw(I_-`ql+EiLgjI^Pj}J{5O5O<#N&+^KM-6@k?0$6M{-Ps`WE0 zMxu+}-h5o|JTbqKt%qjz>e;%RfIsM4?>qOT-Rk|?!^2P>AfrACX~=lGZHQ>kx64*@ z)sbtjPRJ<^pz3{mFlVuWh6pjv996r}OUAbWhv{+OoRrbHarDY?l{2m!!A>M7Pu%)G zv>jMp#5&G6m{-WB)vr?TYgL+Yuu#*>4rw3x7Mc9AeAjegzgX#%pZXgRp~hpv zS_C1<%^)DyYJ&M0%nl;+-%3%3YO>8W9hS4&S~$Yn`lz$PJkdKIH}VrOiR9OpJ%t-5 z8-T3vfA7WHyOq9E1fu9#Z{?k%qmubeejgY`P&zim#Q>B^odGVyJ_t)M9WR zZHo{z+X7SKwDqi;txYM{79d!2x^ky?2<^Hf!9_TOl*%4NWzJmLiR!f4HX24sZa8db zElI$)=}2~_qXDSq-RSAV4NXF5csvbf4aqxbMFAV`ax%gkgTAG?9u2;0-9Sq31MJQX zC`S{7e`hLgxxb`oinF!;Zj8Dewq8Yc>9c*{Jo4ExR9lY#@X*Dd7j<)XzJcC3BPs32A|o&LcM!w* z3xtGu)pQ3*jtTH7nz|t;0I(M%?PKZ1#~vE-{_sr++JD!yVxm( zVflpujze+p(P-Is!pLlQ1pspINDoWRhWXbI9m$*9ddtdl_*tS_-r2q!0z0`**%9l*ws+0F)DKze#$kIXrbXm>_-#{6B5Fx#4la$e5*H=x|;x8d6k&cWcYpwD}Plt(7aUgZdlV=y-<>9=jZVvk?;^~vfd4j z+C9ygEyB8;+6cVH*p)CNqBRgBZz9RA%;j{s8TDdSc-mar?XJhMG~z^3pg?tuP$$VQ zTy*IyHZ7atdM|#N?zQfP*i=@U+C#sxy`HXk;t=m%#C>s}x-%Zj(p~pcb4|`R&RtgA z#~j?uStV$B%4?s#Jy~%-az|6PqaVlAHnJB@)wSYI{f<=Sis|=Pikm+<4#IDMdl#S) z(aT4MlraPMV~9fM{^_6*N5P6O!KQ`^om4j5ypAG2Kd{ds!(TRT&8_48%e**x508_G zr)ol?)g{>W;Lf+O=_kd^91y+iY31LofUoNo_9b0Pax@sJ({kf9@HEonrUw~Tor+n> zkq%JD-X-{RW-LGOskcG*%P+8HM=88V?BL$FXQ@WDcwwWa^D z-pJHdYx3>s7oowOLw~pBaQJo{P?9qnir5o1lzhB0sltlxIVf&vbG%tWE80&s-HMnm zDoM=x?8u|5j??SGLsJqX%aiZ^hu)FQz8zm*icRkwj@FKUB%P)Ho9iBE_4`gQuy(;y z4O;qU8rv#n*AI$8?-sfiJOZ1}lT9TJCTT3yhXCTG!DyBv*wX?Y%Vh-5dq2ME8+L#O zaMDM*9}f#6LOOeTd?@G_bfOAz_}|f5yLX%G!x|}3`1N*8kuRsf#WBS=H&@-|dB3OM zB<2@5_9kwWhNb&YaoxL+OU6cfWhDBe%Y5gZ^&YW7kx(@&{KP zTF|Q8*s5(`)a_-x0d8tw_r9@wiI+%$ljd2~yTmVwLyN-zf6cPM9*%th{%vhI2~0F* zy)pC+#^SX1cX8*D;{Y~wRPNnEBwHK7UB`|Geeu#ra`3Zy3-Mys7q{)?HQh*oVxG3{ zBEB#Fe!MwxpeDf5JJr-$5AhpY{?M{az6q`3MuAGR_dR`T3%aUD_JHNijeAqXQ$kpL>dxDc3rEF15L~(U5&H zxM&6ob*-vwdQ}Ic3G!9g`Ko3ts!Ox6NDbnKb>^hD{Y8%LZp5ZL&~VL+L!Uu0s5K`P z!`Lj(0_(d)l5aJDqb)D(p5pWmL6NsPX=X=ZXupxOsctO1BlR^9b?m6&7Q5eXGFZe6 z#cg7pjELF6?_j2fog*B_FKD%=#T*+_EgB-C$31>u6W3y-K;{v?(4vLRDa$u!0?n;a zBmO-?3*CJ2+S>xy(_wJMZ^V>M&Pf%Q>NFzCv~Ni*WpB*-HA3gTPn7qYi(>GX(d>bW z)z1JpQalxa)?EdJ>apty3rQ5WzXcqWuF~YUC*7_$j|>@NqM7#W!BxL#&7yh^gGIgFma2WX+a8euD{@?~eV_Vxpsu|u_16mO*kh!z`_G%OA%R`h z9y#QWP17}<6uM1jDP$iHou4LjvLf(f?Y)%#Ve^y|*E%i5zwr6qWb+MCNaK{3JDFMI zF7o@mmv-gxqyK!sU*%R9V(OhS@V4MV(xuFle0ri^*``8JUq!PYcq>>&8A(>=X_`$T z)#{Z|xO{vg`kGUh}6wnptze~6~fH22-zX`${E1`G!22X_{c zZ=rZ`&(*!gT?c>Xj_yG|?Yp=$)CWwuup_uv%DA}w91Y+4>@7HSeF#gsVnF}afd{Uz z1TC?cw%AU&$Bzw9yIJQNkW~0sKgV%yAffUV_n^MlS5~4P4!38uuYH%^;zuc?1UG82 zXAe(U%%Dpyt!2j0ldyNu$9Z+0$U=eZoS;lEyW0E>r4c19GNdvCfr(z(y{~#-mZif$ zs_DEJ$y~7HB4ulG@j*?ycNPG{oisL&vyq?L)H~56*JZjN2FBgHj60pWbKtrIgSE2} zP|p3wLrGRh63M$kC@=C6VyWNX?VlQU3-s8$?DJQtZX3DtLfbImjK0SDLIl6g<2%8R zYR^YA()83uMl#B65CP3P+`$gHHNCxoOBP!E5h)Pu(>;Z)Atr>;&R;5cR{QTT^G(@) z+>g?HE#iu{b*t9sk`2y<|@@B}V*kmHY&s!xcpD>~IfuXk|>65Xl{Q|}}iR$9DZwPKiSa!S) zweO;p%Sxc3t?OM6OfO}5D0Vg(y^eEA%{yjZ%925z(<{chxHnSW-bpTe%1ZA$_I?!g zQShP;aZf!10HR(so!)WFe*MtcDab`pXng5?LBoW{bf4vun+l@(x(Yu+Ts41$UAXkV zjFW3q>Au{t*!xA5t`^N0n0=uiT8Y`(B~k}X-yO-isPxWYoulT9|R{CpfzAGd~t`Ua*!PMh;o`vHcRjeK{$cpOZk z-LF1jfmVi?$0KivOE;~_9JsG`=#bbhF&&hiGkafL$i+7(2w_1Bo?K_rSNE-!^ zJRnB8dQF7(A5o1h&vn(&euPnb_Fo&Jz;u&wQxv;j-c6eh;qR#Vp0L87$i0PQT#gba z$#)dsz9$HLafCA07V)eRHgOw8qsK;zVAY0F6J*T@DR`2Ta!Pal=!As?9+Rp)brv_d z8VYVN(&pv_?hgyes?IDDLb=XCaRy>r#wkRNTQ$J{@ri3^=6XdtzC&ag4IjsS9sZ7i z&bI(~-1dCaaElJtsc%~R=&Xe`SMa_#@vR$htpAZs4hGwr7+PN|E3q*r9BW+l7q9nY zz64>ej1=7NeLA#XzBmjN3h}7~8aAaou%WJb)Yw++B8vi#bAoaZLCqI#M7{B*(&Y>U zCVFM}{?z+ZS;PR9JAE|gcf*p4ldhnjBh7Qp*OW2Yc;9U9+yFB&F1ru$(qzVxnf z)~T;rTs8j)I~nE6Qf^@VBFS&P#o!oSj(Aks=0DsmZrAHb@w%sv^5wq&;Q+Ksp1D23 zH3-7-b@LCsVQdqK{&DL*-tfjuIXAS&>;oJ>_ukzlOfu?u z_c`|(cOJv$28?@KTldnvVXdM6iqV?G_D;YV_apb?{V0x63yAwpO5fw&6+=&J;NauQ!ia-3HqtzJgQhrGD_m^0z z=LArWzmoFVu+9oXU5TvEPr*q0>i*racf=79mGi>E^KfjmTfR+g?Ac~sqF&~9+Ceuy zxp9jBR8Zer#oeOcR}!1Oi;@N$RLD1W&V(t0-0Hn8Vf~bw>MY!inLqep*%6HoP(Xdl_1D8Hoz8BmNp13>+ z05gvaKSissK>f*$BaJ(96q#zNc#~E#8GXC=0x9X8PO#nXTA<_}j$W6*=zWA_)y*Kp zopa><&BwLhE#j|t=GgiT274{Srv?l`NAF%!oI$oEIBhq9L>V08iQW6E0<$Wkd-r>e zTi0m62ylAO$|D&w&ww;OeRJG?wXCzEP=7S?)7ukujnj|0pNKC;yC5%kPq9pN-|$tf z^EL5Au9>$4^*S3X`Z{QXwY>Y=+qqj)AA$$c%VdWU+JGbW>ZMnd3>~<7uT!36rc(0k zjgp@40Mv5z%Q?=~RChT2t7&noaP=NiJ;PrDd7eF@-uMJSA5sYnIWubU34)66g9E&; zHmY(PXuf1JSHsI3lvRywTk&m&QnUbk7I(G=K&#k$s-(2hTU#vB#_^>N+Brf)H|~^o z6AKSTE7rSDA_J)kcc!Chq{#|-MBkhE*0v*5-h?qpUGkibL9nRpMS{b2%OnXG4o0JS zZzKiE+DzqiQ`PSP=mjf>tR>)6Pv(@7m?0o|I!F>c9mqPKBpL|lnF}yNBELaK016=m zqq$2Z<|)jPstk@xK!y>2+@mBn42x#}8)HnwxEJ1|mrv#d`oi78?4)aCrCgKdMYLbz zRD>&z33VrI_Lk4-^DLX9nU1J;X1oL2==KP3_4-t>p1O&<#F3yzt1vA^0-pvPM*l{~ zXs#XqmZ4VP5fNwItST7pksBvi*iLEhX}Vs*?Zqdu3T8pl(V@F(xCyiuu<^4%LW=AN zl$Y#Q@gjvIM@h{0V8C1YLyOC&Q-~7_FGVYkyU)FZQm4;`?H)84cr`&B(%OZF-NmzA zJ?UMY-MRO+Ew}dq=HX)oh;(d zTn2hu6W`c4mWuns=!?tWkN`!RaW0A9&Fp16YkuPmAY>j+=qKB-{Tu#eg4k&@O!gwW zBB7@}_58<Su-?Z{o!4^5Hj1>O9IO9!#HR=EPJ$GDeCUei}O1mgrcZMHgl;MxxUWHrkn>tYdCfgU-VJlS~{DIGv=&b6SL20qHCvT z-kk|1deJen#NJh*Myg%Wiykev0FPoCO1kNlTatZskq|#j(uZt}8j2#6=zqt5o3a@HE~Yi$n3a@P}^a8s9@FAE?)qG@H4 zZ~_}tzA_T28zoj!{u=c1{P4%7(kQgIgL=ftj5SScnXLZGcORTMJ6ff?fdIqGKd`6) z2gcTv2|C)&yO778SVCSIhTdDfTjg6D!KS3q(J%O2Tcu5-ZxQg~EXJLinj|wTd*hl1 zSA8S(CwZThMB>E{C3P*m+nbj8uSD{?6$o-2>|?xD!s8Bizr7SUJ2{enC@C ze?UcF>p&w3@H<6_zXXoF`dTIp(Y@JU65B`Yts%3)x#C(!_iJK?w+7v24+~=X)f73oA`KWyV{rNZ8~xqip+WI-Q8DtW|28<@}}9kaR?R@9vw}h$)nnhymwTZCy>Vk zj#n>|`3&tepsOAT8;N2Cd|7Q<9!+-7+^B6~yF^HY`9xnVH{N=2z7&wEs5mQ=yiJw! z3#Vi#VQ@Vp9SQR}AMv(KyHR3q!Kt`tizK>MQS`}DS7H;P2F|6V$;K?`(3cygxche7 zAGZf5x^KNKf7J1%VJW5;J@M9ekazD;!pl94miPVfV@|t|=#l=)hSNS@7OYN2-^N-c z9=ZM?flD%DWp5N3uKLFUQD5@@Y^!aTt?Pt1(5#nUO!RR+9ipxrJ{*sVJg@fA0^+U* zkelm61r0#6uvszTLI#umc<`0fQQVQn+h{c{-@khww8dM$%v2wB{OZIxaP2Z^%2P{| zH%GYD)so*QEk6N$>?B9y)^R8&%1H0c-dEtrs}b)^D$%V8Zia}am+%BXSFVs#3s0_u zImW)3XPm~a-SQs8z}i);7{F>OMU%Q}*aDhJ93i+S5L}_=REcJ+U6rV7S-Z-_3)rbB zX%<~eEJXA@btAn{wuE6ibuG77EZ)GaTPP-$%lfNG5jSBhS59nGvE*Kc3`UH-xcG)A zrM_l+5jh+YP=ZTu5&u3hjUPvsyi0jE5PaFTr8Y3d89YKQBVP|-uXHGyE|z*Z0yw|u zf`xr~z1PT`ps%Rebn0^zWAv5>gQUjoodvgkd{?X8VB`7nvc;{*ULUnA&W^TU!$!c5 z{cn1--2$W@=HUr|rd$)Qj$U;0A9fw2-r8`={_I6|B>SLk_u@dc6X?6mzC++zD2MaX zcQn!LfD5kUg|y{|w`N$JwLG(G--RSs{ZG|9K~byXFy#x;{loqeC~SFa>1;A?Hz08z z*SeLa_pm@N-y0_Sp<`yr-c_MSs$J1UPs=Sper%znVWZiamTIrOHzI11J}%t2Ytp;e zaP+nt>2!i=XMUZ_P2jw`l9^tZYA>$Z-WQQ=k=TpcE6(mGwz+eKVsnAIPyJ50C$8hQ z4M6=^%VZKi()GrHEBZ}J4i!hF0{Ts#N<^$(K}g{+yL2X{d_Ew>!DkEc6wxhrp{`+5 zt1U9N$0kwP=TMrh+2%;Goo+hxs@AO|$OuQqFZW&s7>-C4#ubyK>&q|L9O_=(o2$weE7Q!j-qH zwSe3XuxVIp?%nITN&CX=_6%cl=vv&71+|*FQ?8T4O$(&54i6;NdZTzwTN(lZmq@lzg1210|A$N-=5riUswgec|rJ8fqUQ7``?A)I{9`Q>hK2=?Qj4j zo}rXelSgLKhTa!+A(6fSb-9E)vK?vG^hXz0BZr@Zl1W96#U@$BOfW};PP zwt3z~6yK4S6WGhmZ?l$gnS7RjY2fZjR0Z z|85WeD`wg7VI_xyk)+W^aCG3_A(PSji}-Nivq*vSqAB-2=zRpq)al#j`FBTyZ9Clc zvmBqAOk>c-&7UC94T*9G>hcJ8vRS}!#qBkA+e(z%C~bxHP0I-R(8p|ppkAiKFucGz zU|x_#DxVL+)~5N6s($p_k1Z;}7cmYcbK8^|d0mtJq3fkg&gl9RpML7!eSoy24abU~ zMZ+&?7ZJXS9<3^~t+SiFr82a@n!g|{D9y=>%NVDE`(tgzu}kc;F+e=W&}tkO?-0`z z&yeBxK0IXP_3mvU*{H$qj5nx~!&Nm*zqUKpGm(eiI+pt0ZVzE!=dpo^PI?BpgW#cV zG$qw+HGUbFs7wy^ENkxGHKk0s3|bcCf$R$Tv(#sG`eZ4Il^N_)Lw>e->h?YmLl-_=VY~Mn+J@HtdHc8n zL{snnmL35l6nM0SVQ=()b)??F_I!Ak0b-vzhLqxx87xvd=et-X>5_y1TqVYf#3`+t z9YM&7MVvOdU7_s?covUb(lOi6o$Bo^1|l`sT6--@T$MXivUiV{O20)Lt{xt8+ijF$ z2Z%an=qRpch=R~aaFpC&5p~aSfl4FJ=G<#;$AOOJzk0-7h?H_Fj&5)`B zN12$vu!f-Ba~Z_-GWHuUIuhzelHx~N)M$x$E~rsq5ZR_Mld~~MM{Iru>fB(#8_ezP zDe`zsJ=x2aRi*3A{`TZFZSXjFoeD3c4anxB9Mv#+H)&$F9kt%V!El|x9;>f>&ph@b z)vvkVc=I3YV^1Fkc2d6K35vRdtL`YC74J4q7TQ$YW(od%tjW<4aQC7m=YOiE`H6sw z-Yt2*jW0ol69aH22)_1+ra5k24ddz**X7%3sPO}dR<_;ZnI8GHF?&hN-W7yaTpg>p zCqw|#ziYx;z0!u;!^c!}^y*@t8sXbCVd%^zYxaSA=T-+z_(v+jG zb4RDWy0??nUpCiR_tBDnzkK?gBTvwY`w75dR^3nBR|CwD-7wNb$KNL|2zNxfsd-Dk z{b<6;o~ux1ngk16#0SXI>4?4P-(aXKnEkZo$ZqZy)M=`F0jUicvFQDwNFUe4JIiwY zcdE?xmaO5hOt*V~M?9T83YHlm+`F7~w^2sXRZ!IGJDT3+Jsl|gd`Xhz+rgS!a!b^! zLFsTmyhI?%4ZX`-hohz5rN?2Vhx$!OP#pmfMI`Ko2?``h>j4|P8V;O~*{G~bx1M@O z8-cgHCFTT3mrB{aSH07b4;`)>#P+7CX7z3#&IlNsp5$-W3u7-H021cgHXU&6y_E9U zJy%Dik^NYVyt&WOQ2{oY@Gx0z?+(}84E*TK?_)Cg@8G z@O78Zdi;HF59v)?0IuZa$?qewVZDPGFQ@x#@aD{8E3(`B)WWbUsHRf=eTS5>$D)yx zz~VXS+}=0V90ci3iNAx$lywm44Fae!#WuDyLSw)5j{ntscP=}4i(opyb&27bDC7FS zLT-Gp9-Qn1ZRodA7ge-TKo8G~L|=$sI&;lTLusRT8*2G-;%^C}XA8)#$!=TlHr1Vn zCl!&g=<#2A^_^?lA;2rkh`g}$16KABL*{jYk>Sms#5V(=!D^vUpqELo(dvWyBhWmm z==82F??ne|UdgSfZ|~9JZ>G9K5Xv2TkGK9A;p`0}ebM7s>7i!dN1%EESbBNp!N&ih zE9Yml?|!@o*hbXO1{P|Ltl z!~Ex+#=4uv-k>KF@ubx6Ji2eYFY>l^ty0o=&~P1XwB;^`?;a@qjCH;HRkU{k+#c7C zx7V*o%e_PgYt#V%?_eaPFG?a3MRxQ)BAV5cg5G^0)d@o^2awf9(hiCbDWbZ)M}r@Y zG;|aFA+_pzeaHWB_+j+A4?yRz_eauBZjO@=^S#VppRc`-Qa-_&YDV{N|10F?`X#>z zG1YhCYnLmcUs0q-sy{pXf2Y7nHcH#xZKx%r?X#ty9|6>RPIfQ99IhW$epN(9>v8|b zG7XgVm?nCstd^zs05^MxA@e%H$nfT)-WdSkwfdw`;M;%UsM;&#(&eDxJuS3Oc?_WI zs8VO8Ximu5JPN5*BeiC>lu(DF!f`ZMo!Y<8Q{1hwM|)M{Q}3w0HTS&wmb0RNjr#P0 zR@TI1Dmq;CcoCO)Yo!%{Eox{8ayaVVj5esI1V9ReWC{d{fJhBNK#b@bua?~VT+~pi zm*kziQud7iWuQ0^dUu-iyTIVGu_ZzpT-zeDcS-I&JG)jwBVHC)Q8F{o65L2mT(=Md z{O>ho`KW>Ze&X>ms2i08?rGvZ<=Wb;bD0`1bbSLT-3-79GL6Ghyy1cieV%-lW3$j4@@=?{tP%Rm^MKhZrcqP!H)t z`rH+fUCHh&sCBMe(WH?N4|@EGLTUv0h_;E1zEiW~e&LtN3S%Ba=J-lrhxw*A_QW|M zh8T1nq!x;yZM8$I>!tmp?)G@}v!RDA_Ep20TXI{}!;{lJ*DL-f0#Ux`UEVtGE%h!v z4!1ni&xC~P3P6;Q*o_H}NJ{G;7}M#xZ7W{B7d3?2dZ&$r_xPU7IYO4VB|~%n%-wui z@4ixR*?Yw@CD?q(=k@kHMNd2jaDv1_;2`-*$o9S7DmJ~Vob__>@51lF{a`3Vw zl48H{#S3@6Ov@OE^TOIBYDv8rFtN9`Xr}2D{YBy`*Nw=3ah;= zGh|7AnO=WeAZ2F3by$rZvIR9gu?^bX`;@^7oL%foQeG)k486H~ARYxX5_?eR$B36K zIbl$515k_aOm};C1Ukw-71;@lnr*tZr~@+e4q19n%H3QQ@~`~y;tM5rfL?BqlAT({ zVzKEzEwttwtRtRbeM|2*$f8sD+j}Pr_}i>E#5vTs+%mm0pJ>=J8eNVY60vmO?Gm_c zRzWK8Oe1PSS}6<77UK?`J&M9hkSzIqLFr+IHNm#jc_jS9X-1AJpRo8)Y<|gWk2$725})y;FUM$|J0| z^s4zGxp{(RpF~PMi+gXq&&agBMyJP!^A)oWG`;f~F?HVaHL>naP=37sq(mJ@c`pmB zU{k+JX`eyBQAcSbwHH-AA*HU9-iPG<=d-SX2i_A6#4mk0)i?msI~XJQYl_FNDoA`Y zFd9o^hirov#507qLodGFE-bf)Xv;k#(U6pPvE2B-8Y<@)`Srf-;SngeTb%?FyVN-b zpr_?%R`b{(VMNf)jJA5G42Ks-b$k>+L8!)Qw$Uw$g6fXmNs-=9=g7UP1V8yroRs&? z9i)`$Pcjg@1(iQ@%vI4h7spm(z0>>sL{5?~=~sxiDD7?5`*pAX;+R=W#bjrl*(RY+ z6x>ES%O&wLqTGE&59qXgO^WEC5$UgB=+~vqO$4v5(hqQ}=y;G4xmJ3hsWa@fZ=gCpQoY0;H@z~uW2%LguV$3FSZ+2(- z4gNyM*TdlOS|QY@?XFn~!G**9j2>)Kz4N%Lp81jJyBn!EZ#*e4Q7|(4YUpfm(rinC zHm$xEl{XFlfJCQ%B#-YR;aHCV@^SiJT!`hLR zgLT*!#CxNa8(;vQwuU|(;hX`G2v-m-sVe7;Au?&wIhX^hQ<*bzL^r@?NA!~2NWLQH z=yrp(9Xuy5PpNJ5-w{AW6tB4@EGrbv)5!CoFg}(!#8V-{W412s(2qD_c_@6&1@2NP9EX>y@0xSmqK!-AUFL# zD89=w|AL+bUeEIdIpvQwd^3>7tKYY??*v|rUdyR3fLShGL168tNS1AajRU?;)1;(N zpAU_dB-dG+pd6U*?XElx{Q=<1zV z7gB~#r#Rvc6a{zs=7xQ@y#3L?n@3<{0A<$1y-|CoLszCCxrYNwq`MtDp2EnOxf_${@5McRvL@+{VcUc<(n4O;cVJmHK?EU1X zag2WH9sb&a9P`gAIHX1{{GmKod%%#e1|YOCOg!AX1vJXtB?&mXRLoWH^v!>~4{9E? zsF5+jN(Apa5FH`}?Yyg;R@7Y>UG+YF=%TnB`T}&*i7Q`l=d|-dop;KFzukg24{)tl zY=i^crX95I zuvbfeu*1G8%8=bky+wk&Z`wJ%SMA*vT}eP(K4rm@U*h_9Q-?6}OpV7!*Okp~kq-k* zC!Jt1pAGB%yI#0tz``G^C@N&7GHe>{#@zH?grQwzvE7CBAZ*k=Tygf-BCi4W4dd8* zLGbF(GymKz5gM4h4#iG;=^b}lIJ7Y)Uia?pg!w*6yp|{iD%xULu1NzYoMEOgt?%Cd*;TN;OgMC3CR-&Tu4WEKK(r>QMKa6 z)HidEZkDsdIy2g;?M8be$#ZY_A)xV=1v}nD5Y)OUx_);M^0$fz+dTo;_JVPfdeP=r z_q`;awzm)6#h^^*6g-B<6ay<_Q$wvnK%F*9*}yDP80 z1gNP$%KqHO{iVp4?dCwYpa~PbqZlP5BOp1WPH-SWxzts8ryuz!isnQN`N}My*(&wc zVB=5-q26S?(5p>nM?ty5$rmZ$-h#`fZx^3lQr9gQ>_hS*mWg{dob6J)Cfi$$M9b=N zo~Jgn*7ho!0xnpa^w(m_+3$o|@}fqeHFGGsn~{jcZZuPDyUheQ)aue)8_0yT0~t7x z;G0OMQb2H#{u}&`9ukq?g5o=w;@}3DFdE?&Awko;Nl+Y7&taVr9;wchqggN|Q<%~` z`E~&6dY*NZKX2;O>&$No48 zi8lU|!e7gXc4ow5oXsphqL=`ifcEBsqg%~P`AB{#?3K}051AmReazHd_fb2y zyOP)Vw}^SO$PNQbq`L)O9$RzeY)P`;-kg9=M%xRUonSGa4eO2T#Sl4Mw}z@2nMfeN z3l4o=UXBPxh;}K$X~WG<&rR%yR$lhLa?`kv{?a@Cx`Leja|&KklZ(HU=V=d&2x|a2 zWCRnBd#`||TuMPcdm)S`y^jdCc6mN=efsKn@{_BCK6fa(7PW)CwN}9GiUCCMW1 zh^ZWoP zmyNdc-hWvuXD{o%n2%=fkj4$>aJ$u+2b%ZU;NZ7MM{l_O#Cme=6#rpYA?~0Y^R8?- zdZJ;Ma~1@$+4O!y2(o=kbv|+E$b+^%x!m=LGpxCK-W_L6x9=R)uiaO&p00Y+5I3KP zBp;npy^~I|o^n1^H$-d#3Y9y&U-0diIo44LvZ})?qs`v)gt;8~M5`{2l_R#YM%HvW zMz&+BcwHKGXy-6!{?JqO@b9qL8?((jDDQ{mz`ubZWjIf*4wQ0-p;ip%otj2vQ zChR7I)X*(q5e)`^7ZRcwrS%<}m*H|`IB65$ zrK(#I9*D^8%x!P;(cdT7k)KXA!Lj8+oUbF!_MVM6B0Ie|$L!hmb}Tk=)kKbVA90=~ zxzjsh;%+T;rMgGNC7@8b!}}MMGI#w;1EZd%d+_S$<%gezw`6$2e%+SK#hr<&xw zZ~bNbt?5_pY>jX^)+{?M)g3mxgqNmOzx8(p>%L!c2cWqw>N$!PeHnguZAdn$2GI}Fy!$t1pMSc-v;yQ;-8_4qRznhvc9-(KU33$QE$iYA8LqH z_s8C=*5CcM-kq`ZN-dhe|*HSB)VZs=*lbc(8{6!y;P8Wfnj{ZppmrXila1}!AmQd_Nx-ZlJqhh;^M zVtGdZh^5G?h;O8W!kcniHqT~@hTM_uXf@_K0l^#M0~9#LBT$L-T?CBdsBzX#5;cxj z3Upp%^0v&moT)kEb88s3_u?Emh50f@jv5hV91!=|l2a?*RCBO8n&KpIVP>gygSRb% z3>6UxXItEPIJO<%e#CRUdu%=DkOflYJwxc)a>K`K#}<<{!`>0{G2R@IJF)&SVSO~_ z)ldR>#o3z><#I(^VCn7}Aad?B&ea+VbMdxKuqsThI|ICtRR&z8!LoaJ-KZ$&p!YG| zP~V_AJF3z|HCYRViu<_tmen%iGS34*xoosY@BPVoa`v?Dnh|u@V6Q`SPtyZT1b{R%y6CnZW~Z_#=4ghZweHttl@ou>&uHs z(p|CKdzUmTb1mqYDI#FPuwhc26tfmin(SGhjPoYJ_&Qx7kUqb(6DT59tQUMSTU*h-~P-*Ih%#} zJx){M6I9g)8oO-Ud5Lld5Zr?2ir#mnnb8pC^ED(lsbr~wa(`7fxWTAZBdyvf5(1Gv;Io_p~g96X22NC{)4u7V4w9^}Ux697AwT5P_q_{Wq zo=`b1ZBrg1#J{BX804M2{P`&#MD5GbBoHFD$HxHn^j^2#^-GYlLB*#F=;cf$H17Y! zLkkVDBzNFUUD4+6rm5c_lD%iQtxno=@xW?zQ3e{`cCEKpuncBvjlLWP+_Kw}!SUPE z*t-vx>LQ0fVO|t?QRnxDkpy7AMPcKi zN3Ac2Lozx3`CmJ-E&KW7Z5c70aIdVpQQl!f+PxPR_*gdfXpdiv zG^&eQ7w}(Cz`c!sbA1$1Q5{27pK#rLlKyng-5R{Uzgv7K#XV#1KHIi$`*usuDM@%v zNctC68o0FLYl%Pa-%@Qe$_jJoy&<;aF#rHP*jiY8C~xa*Y4xd;fIOeVTxh7?sPn!> zBO$p(G&54yJZb8A_3Rbob4v?rJ$O7hC@T%zi#iUh!D_AV054&_>h48DkKg}8jsv!7 zaMB0iEaZP2#QPPMR#&Tcy_eaL`Vl45R7-ZxQGxR0{WM8kf`@s}zoFzWr^B_qd-Hn+ za-#R%y?xy~fbX*DWYYc;1aJjEC?^w37n)Dsp%?>L$9tN}1^2;w7Lb@Al!?<=*;}ic z7$YHCSFPK#v>|f!NxXmwWq%aMms4zm_(ewJlzoex7E$gvap{LG1>jESZwJ%DfLkUT znw5xK7b`90*Ra_F%fO~vRNA!iQ`CP8KUg&HQ%PL|GzKT{#^H>V<=PCK=|HPcG^q0U zeS{LRKLqwDAIx%t7WSa09PGr^!U5tg>{llBt@pgbWrI#(KKTumVeC<(_U;j^ZO=u^ zhHVRjlg(xNi9Xc_`k9>#4W~CNGpj#q(Hs1}V&%spznz6%U?;(k3F!$_sOawacnIG` z4#%6{YVe|lH5$BXT}=r&?|h((=1atl%DawtCm+ zLmg;{@_FHl<cqqMp~9CHH-JiNyUDoiY((Rm!Vss6&D=T5@ELnu-3k z_H|kfkAIa|RIRd_Ro`4b6fYFsaZGwbSL1%z2Y8muXnGw z>;FZd*OAM-U6d)Tvo~T*e=25QiFr$1zBP9_d*qf5Uyq%0tUG-@D*YaTAfuiM5@NnU z)0HF_p-Bq3y}-TbOe%{!bH9MO|2jU#OXQKN`W1IW;9{$H{h|6|y>*gkDX1;(6^4Bp65reuH$# zDdnsn7hV(*(ZJZJQS6mgw_IO4bMi1bd!Eb|;!O$MOD~?ZcXb^N{MgkWJ|9mqGR$X7 zV=sMvSQ2htrWyjE_mqI_MuL%tfwv&9BtlC@TpX# z-Mwyj@bAcNg?PS3vrY=W@ZxGjI@r?T&q>y~>eu5zMwa<(YWz<>aFnk*M6NS zfPF|I^vyM9&hLSeFVuW#cUC``;LfJ^9TRN8jyq59$&;7oRX0Aik|+lz`a4}V@eaOT zXP!iYk-}l?QOXhYw}KxRpJ{F0qY~M@sQL5o{rkH)V)yTIkT-&d_hV=p@`<+`cg=7P zB!PMHO3}`uoY{%%NmmCQLZaj|%2_n^Tb;Q)A4KU{Gw%U)4n5P0H|?FSt80ID_4VsP z@e5o+99&;XpUCz(vNzs2{BAl*+Bgxh!5!cE@fnji@B7B5oORo!!3n)c8dlRTWYYJ( z-OSzd&a}VD<+}xH2@a)f_5Deek6HJ$I^{T9gavn7;hRB0z0T|Q;5akjbc{|DAkKSF z(6?jck~72x8OkS|(#**9k|XvXgc$hEnfurPa=SttSzoh$e-yVv(6`yp;Tm{)kE>oK z^tR@=cG@ZjCP%og(|+YO)e(Rf$$y6|uiS}(6%6hJ9D+il zlqj>HKwQ}pWVj3>N&(Kww7dFiILNsVN$;bG)Sjv-Czw1|+AN87-?v3lr<=AIb^VWU zdMp&;k|?p#4ZEPwtE*54p_z59Ru==W^qY-jixu74f?M=D>i}v%mA}oWQt-_faCk4( z-i%hJBLVej@CYPzk%@{p1J=~C@S|V-gav-rw zjn3fx!`u@j?kshjhn!UxAec{9v7HIq2f=i73H{k^d@G3KCP|g0QsTwmE!$joG4Oeg z%BbY!pljUozpTKqJZB3zi40%|bAlgiW z?NZzhDS0{b#1jXDOZ#eGJXVEJXfL#Py7s4}pqG0d%2n^w*y#Nu)ClO(?yUY0fD1l= ztKin=n6B>Lm%V?`ps~9Zk_v?)+Dsh0majLQ5)q6Pj;%*2N6?>u^5&;&?HKsGsQI?F zeKyB<_5Qi^3vxP`ggs4r;<2MO`}+Pge7+XU+g*>5ZQ&zPBe73=eD8HH>6nIkbe^2I zGt5r*-*~WmDZmapt0nMUKiXg`gU1C4TpsxST4?|S_f*Jgo{bxq-)u_SL8<(?f$@PG{7@of01GS|x@qGng`!R4P) zfe%q1yxZH{#DzlCkp`&+jow%IW6pxKww=ABIy37I13Ddf&ABlL%Me(!5shK(yX|k5DPrg z+ve5%r4yKp?C9WeG#P{s9kq44qQUp-Kuv6>6Dix^S@3 zSA&rHc9coZJ|XGc>G~z3t0WeQY;zeW|8k0}MBVnO-}H14dfIIlX^PB z{K2vhg~*Qko}dxaG0PCEw#`ZaJok9^D0V1~YVX&SG1BVmDKe5eq^Np5yjiAzVZK&Y z`JF(@YJiuy?c;|7L1(E+hx|Uq$tZSA_#(&`jHUOmv11{BaLM`~_KhU3^tO3*d+h`! z3%eybjWYglGH@Qc>GmI^!EEDkfLp03oTFwBU(oyA^V@#BNNxj3?}8}Z?Isey2<#pt zC-m**?Qs(^2hG8VRYDx#M(;ODApu=@IPGQATfNhHNAHyLa@P-x{?0*@@dqZ7I=vq? z{y68?wY$Mt#4QgH2wyRN7cw($2mZGWk`GeNap4y4K3M}L&52@`5-_0FU;7FqcA)!J z{Ud>2MgF!th|XQte>auAJ6Xv3VbA`8%dGfBg2Ezck^!^W>#bLRI`5Z%H%|0Unw8hR zXFYQ5(L3kAoedPTl4-Kr$jin94n*T+;G-KEBf1#Q_(Ry(EPV%kNGYg8<_rmdd}?51~ePml}WrWR6b6*xX*BlzSJ zWk2PA^qeFgniNeBUATyM9v#KnTVmqrya^B3Mo&jMZU|*7+6_$Mnl*vxG331Xz}(%y z@FgxqK#t-uSqjKl6v{x1CzA?r^`MsNS(o;x>lqa26lTM-vajEmWEM5>;U@iTz5#w8 zw7NMuL}r#aXs#|kog?pKq(zuM5_kc)1vr6vG0&&h=axho0$sS`J&qk0E?X|H%D=|? z8aPX?jBd?h;F|MQl3Py)+q_c4_TSL!6xr!hPlU9Of;<$0zDJ)vvcSR&vVEr@hXIFT zj#4HYy|kTn{IMy?<&+=hvn9bxx1U&#GJ;x_xn35Ln!S3LZC5JrAyfY$2l@_{Jql4r z8l)C9dVj(fSMCUK|K0cWV~E}_*xX*EH>F0}rjNaY0x6)HZCZ*UhY_*o?Y~mTvd2MPV>mpR=_JcH+IOOQg4{s)dcQgD z=J5Doxynkh$2Rt!Qd8lsy3?p~Si$oD{=R?U|Nf8vng93TVg4VLhxlKQhyOeOZ=}W} z;D4|G=O6!z^Y9=3yRGpt)Bo^Kah{0(ho?CH7boKQ->HZH$LT*+5C0eaPt`;JH4gthh&cR*>!JVYdiX!_ zUtSOS?>CP8H$ue!$NyFT`5*XiV~zM%vBrN-{|0-Qf6H;yzvnpqC;ylKc#4GiI=$c=>9eedCoDIR)>>5jX;sT)#dx7qKf%kSe)quzS-7`S^qA6SJw^0e>wkV^7wz< z{-w#$|DXP!wEwxI|Mw05Up4h^hVN&-nf^P=vA)Io8Evx!wD*2FL=G_UzhWNiKVu&8 zSNLzgM8B6wj9c%9jT3?Yum9=rpR0)f6aFs4|Ne6Hf3YIsKfxUFx0(DK&Hp$5YcTQf zUtx~;JI(Ju!yHe4r{Ujbe*g3P`^>-hpK~gk`hH|H6Xk5`KzyzI5JX}xqvd&$#Up&Y zJ?=h#NOjIDDQ-QUT~AD&DBj^uq=;`a-R->}S?(JbKI(egv63_F-NV3B$n)3rqKThH zVb;le)>TT70*c*jY}TQegHXYA!-T`{qc!bX3Dds7^m}nV_li?jhx#V<*tu)Zh~~1> zcCTXKw@pY?PtePQ^M10qOZ#qIM8bKq-#DCY304DEg`KjeS~MpxW|wkreM8q*73;T_ zac?P%n~2n3S!E$NtE%1C$_lE>(XrJ5r__l zb37ry0^*}xK%VQ@t zU^}F~+jlRs-c{F&GOsFdd%1Sis+QR`2iLt8#q##`D{KV=4xEsW?oz@NnWeZBAb23G z``un%Em>}wsg9^C$^*umBjcf_nOcw=m52h)`WQGAx!!}=<)2UiH6ZN{HGfSTuDU@= z+0E?SQX&DqKmkD)u;k*;b^J1brbqbI;l3wiv zWnprx;m5G|6Fk63+GCeCg~3o#=-}D=G6lX}@GVu~=1eemwxuXM^#mxqVf*?t`R;4}U#@BcM6uKs`We zJByLPmLMl+fA)?@aL>mA;NNus*h+toy#rf&rlCnyi4N(Qrva|D0+Da;P9WYNpiCRq z6zRofNeHO$=$%mFm=Koj?3cak@*CCno15CuUmm!F$!-LEQtB>3u**|jr=Sncp3o=z zF1c=SmL^l4UjxHj?aSB;}aEl%x!9jP|F z^OjTjH?c1S^6TGgPVN8h|H!FPs{JRDYSpQgf7Nk3{Qk+m@Hl=K{F8t3-~IRh zp$F5e>c+;hIf!mIK7B=#$3;q}=xE(_BYd#I7;Y|s8b{Uh@k@f8j1bB3=49UnoiO=O z&C>20rLM@F;P&nk&07n)=s$~2Qu7>Xe;7rNrdLKYzn)4-j)!h_`OL&efTOwLpeK9Z z!NE&8bHG3@mwy>r7S{o9f6k9p{N^CiVEKG{(9a#fPWm6s(tBpVxhic=sLJ@eEO+8s zD?@g+VekL<|Lp&=$#Zq~f0F;_j{e^=U&F&Ut9LZ~;{O(>{BQScyr1w=-#_^;Hs8dE>)oe$)*AEkXHz`A__xHIH*TPQb%v|I7SWnB)9i z=J&YSpFe8Gzs=15{LjC?%ltS0!N33S{^wj(rJgmDsrfkWn+fszAjyw|*(5V2yc!;Tg_en4#zf6{v(a99)#`kx9+GP&@tit#}ZJg!P=B^AK+wyJ8PH3c(1F9 zZ0x&wG58VrQ})fN)*NSI03Tl8rj&Ep#IK786dYoJu=Y>Sa+j-Lj{CsbyOc<3ng285 zjD0ss9m*XbKOXNcSrh3udN2AdtlUbZj3<2WZ7Q4xFu^ zY^@T%wPv1*01@w7>fPzVx26K&nfS(4^^A*AN>36I)sD62A5*7k3Z1%g_z}Tn_psl3 zI6XCcZwrjrc`s#Bt&Nm6WqIf0Izmmaj}I#gz@5B1^um>h?tSS_Mh=oo(huAn1$pep z^TcCX1A<3R8z@9ofy#)_^d&N6g^MSf!gLqz(j#i*PI(-);p8ZJD^=SE*wOX0)odB0 z0WNR!D74R!9NKS|#c9aQkq?xRuZxppuv$kQEe?;$819&IoP3@Ka=RJ4H)-z_aI)^n z7}#ZKdkZHSA655|yvnm1k6gnJp@tx*lVVo@oRT-j%x`nN;Go#mJ3!5NAh0(O_(fCi zw&0SvjIEU7Vr2U4ryhFpV`opBU1RMWOjlCo`AGZu5$!-rQ$}-sJ%H%5!MN1izA9Yz z`~~8Ldvf+e;<1XJGYGDJy_p=Qp3e9 zkvnSzkS}-la&&26y_Dn6x{f7LV9bO07f}SUF!%UpSd3A~It1`1{ z<^nV1uRWyRZb7u=_BMT1_`pu?eyzLRoji7mQ)S2nK>H5qD-IL1lh)cJpYd3G&94*5 zkeg8+QYF{bv3C-rVXM~|GPeK)AY(?*4!`FW?6aap=Y|ZN;Ifh4rpNZLgHu&u=W=#C-$ZpvSHK(?KK->}%ET zt+tcui9|y_stIs!C^Qi9iKt&C-a5= z7Y27OKBoZ=|)j&(o2Ta2-&H)pH%2c6z;GFkb5Z?mw92r)A6eclHrPWtHl zVU(NiaNDTurL=9iZCfSZLDq-zrT6U9H6njqX5<+*)y17JTZC$Iy>lk0GXCi1@83(2 z{BQq@|J#4s{O8QO|KE`o-u?fMweWB3-)H`V|IdF8J&XlNyqp(jvio7Z6=%jb#SNe{ z;?Rs`mvb}ax0@eUKzSa3^K)Qdrn#LM9~m#t@GkmUSH9`?$C!AjK|xk0JTCi>Rkq)f zV4V*q>Yhz>kdbSZw8GOvZ$!Nn_a@baWfy0d@d4}dk)tW|qyNb5jUH^aPuuWqC!yGV z%zhKjoy)?5d5w3kiEb)Tx_BPEo%}i=#zfBP$?*{HLfwt;n)6;;twl4IgfyEvx>Ymt zc@5Vl*9dYB*03mwwv=(H!bO#}mpma^LZNlpKM&_bJ^Kc}F+Aarj}v{^zB^+>Uu|pg|#>9i!Y%$`#8-R-A9gZG&^kx669B z>e)yu;WNs9>z=a|H*v2oFx8|8?hmqw+aQJ-TM{v3jAh0P48sP*D%na?+HZLrG9 zV^xfho<_U$E}^tW$E~sf!X7Da*pbrdi^SGv*`Vmdtj`Ec_ZwQW0EiE*S|4gI)AXKN zC`B{edw1_h+lza>dwy_V)ZOgR+{(>8pA+vcja7h@bl=CYhk+@d-MM#)Hq)s-dV41u zs}s4oLr=?!6N>Uifb&D(*etL9g$B{m}6R1y1hr z%i`|8Enz&fM3DPE2s9sVa2^M0+jkG2<@?W z?pT^UcKTVm&ttfC@5q3fB(GcMyQ%(}m_i%j&=U&-(>q6}5g(sUDU5DtdqKkl&%K~E zMnMz95&*bIb!P)99Z2^OXoKzXB0OyRqO#zaqi~PU4U)clj5&pR8UkOM?;$S@Z)~m} zNq2L_v{Ktw7|Cl-+(Qxyprnr^GVB^aS9ng1|HSQd>G?G=`U}>FGgcp$@Spz0U*dnM zIR2C0fBu7i4&IrzuJ$djFKI_i)9p3Chr)Q82KR_I_jOVf_yQQ?(tYnE&(qY>(3^$Y z#1R=4cL{7;>>+h4aSck_b_Ww|wh+L#%JE|EvD~Q`l)A&+nZ>sIqqBK+|Nde4yVS=> zC*0KgP45dK)*37q7BR6xd+R+dF$9jC6P!VYD@DYTgF_`_)ZL=F zg45~^lxGNXfeSwm%K!WS`TzgF{lEI}P>%mu@$_%(-)H{!|NVde|NQ447Us^<;OtV_ZCa z{3ZG%Bo}JKbI0})G3h`_tj;yC4MN-hhvp0_ll|jiIED~~>7?~NSGQCvTwzF@?=CKH4 z&yQNIp2peu3*~P(w)dV~f$sOw@c2C+LLLv_rSnY?2Y;V3tKsqBXTT(rjTjkE-c}yz z40l9!#?0@8f<$*;!|rsrFywkBvyVz$rXKNNTYcMO7GFi&5cRAp+vcL+A<_f|z5upg zZqE*Zs)st?f;i;@Ok)d;-h?Y<0Nej{cy$;{?}fn-zS- zF-w!juAkNCT!wqqJCAT1P@eY&7S%tAC7QPM;AW?dJU4#PtfXkrHfT^SUudlDfg_dK$4RLrvL`L7nuKu*XeB^N~Of=JDT(D;iZmW1~ff?MMz zb(meS)ZmOZ;{?5xPTmAQ)=1ZO5rxrDZiash#t|~W`qDb9+DF-t8|98Xi1&ByL(m9D zid-nCrkj;&cF;adUqvowx^!olv+!Q>;r(_LIFJ zOTG8@mvlQgTEdvcJ*v~WK$Z;f(+MA|Y_YDA)dYfeIkmKbC zObc>%2@avLW=&VegB2N(Pmt7mkk`x`9}lvL5Tf2Rm93gqWPRDY%sX^@ceLT_``*(s zZvXD`5U_>#py$mjAY#8@(_fJ5ry246Z-4s!mx|;6g#VvsjsNGrVl z*|)tT5wVMiWOzO6QS&_XvobAG%vdeAndwmK}0^I;P z?LAM7Cj|9+35!kUO;iyH0mu-VN7LHltIEQAxwnNm@nqVgcX|8^N53FvG4xG*r);Tn zQftY~2m*J0m%6)04b`Dwa#B_a_FYvXWh@i2?^mKrVeL*t#$uG{eO~`v?^}kPixy8JPgj!txp- znWs4SvcOeV=IvV<Wh~(W!Coo&a%qLFd)0Po4NGjSKkJp3%1@ike)M0y521<{+tn~9+%LUj5dJH zxclw_;Q?@h#U{!ks)%ki34cqni{7cE-_q@L;}XV9(ZM#fF_kk-HJvznKTo~$oFu^+ zu3SJ=?IECVDEQ~xTtH36XCn(h zyh`x~yE3lh?%X#pLeue9nHgFyzsM{gZISv8ujj!0As5q$K1iK>@AR0j1iNpoYp-nIM>9iG*vs zJ%-}#pv?kZoP(Ab!AH?f5|?R6{`s>H1eNl#!d{HZL z$6h2lao-oXf7y1)WwyoM8NP_hg|@+O|IyBkX?HXUjR9;?m2r0Mp;CJ5GR`UB+3(Y}E8$y4drWk2?AlSmWDm5V zmS&m(5Jy4ak=c7!{@shQ{IO_Wd&uRMr;hlmIta7WfRrak%M5hbka{Po;8*9m3IA7?!U&guhs3YmXj^YqkI0W8c`Bi8XXvC0jnW%kH`)H+=f*Cl@g6_^|vqR$4+g zd=7g$!BU47u-$cA0F>RAT^}V%h53V%~ppK{npXF&-9)8u_fCG7VAp zos?tm!8qRP2nA*0;ya2aI#v=F8$mkVF? zG)Q+Fvwq9Ia_@iG;qt5jW7rV$u+kp;zDN63w1{LkXuXl$z#P6PBTTiOxf_)tPa`i7 z##y{};%f4mNwWOfZ!g=4hUvz+%bUi0(OmR?ZP`<`+pSCR$Go}hZHuU-!)oc|cFCNG z70ZG};?Pz+)vKB$_*CG%t9$ok_8r2aV*R%2XV1bziEnK=ZXG4t9+BYq{98_CHo@q? ziQ!0a5%Ru~r?6%?QwHdqZzHZtTay(=XDA*Ip^rg5je>0 z9>dv%BwjhJV-eKZ@J1K~Z<&7r@OEOb`+b}q_H=HAH#J379w&_Rj)9l!8f1C55OC}) z6uvB4Vp!J`c~&RM;P*{9jr3c$PIc1Xg_lOY z8=sFO+b-Z8diOnJ;cYMp-|*LC)$Q7&QhIB9ckVrvEq*`02iNl&?J*H=e{(}ECVQX@ z^=hUKKpcZO^R{;@{FdB@y0@?WlhG|qmUq8SC5ejoDiII+{>8urOYTRhh&N{ErEK!A zXt9!2Q0#i$8dyJt`!UJTL*x|>$IF@f$06S~&S#&+P8lTIMZ}qSYsl5=82Veb{D?R% zozYFRG!aXJkt1KG@pj#eJW_MO>UXyAL{L_U?e{6n!%W{xwIvcm0CQiYo33Bv8bpKK zXWjSgKJMukcWETn@%C|pWSns0c?y3R-!#>5(DFlTR<#-Lu9H(gZtE%fpAM z>%a-?{fEe`g_?hyvhUyyM6XT)ubjH0(0FgbD;K`dynmlnXXVdb(9)}!YK@0a8PUvZ zc6nur)w_H;s)Lzkw}p^~qF*R@0@=gcMGvshI6lqqf-YmO$|HxQxLiDGxh^(P;Mm_g zYWU+3liie#`iJPA2((`)?+X|Jn2OZ~T9bIsQNO$(I>! z@5b-dbsv9Y1DA!kG3{skwFhAm=^dsQcfO28$3?#c%FCZoEoV*e|MJ7fupRKtM7wZm z+|l)&k$%r;JsJRFO|5GH^2k z(lMoR#JBVW7b;1P@JWXhgY3O5K$}xz;}8~KvpgK?TVS0cZ-{e9Zzu1Km-im}9ZTSf@bGNB$0n8IT*pb@N(#5Z^X6ivV{OMZMPpl+6gHjcmos@#^N{dy>EG-DA-KMZGV-#ZxHMR-FjMdZ8YipyEH#2QFcf-WZSr|;6rUoH#W68>JBvOcW8L~y(Nw6`Z`$oT@U64 z-=iWa3}oGL4VX4yZb8$*s;2;V-{HiejYz-I2E_1pAe=`r==VF2jf2*wgoGxI1g8p_ z2hA6ov`>CO_lDWR_uClHe0NBgZ~yDh>6w3(9n6>wP%h4C;_abL8Xc!Fu~M^>N~huy zLik7WP)OjRM||Q=h&Q(9^^{H}Yohzvx)12;n`C5VLNeH78FfkMq2Z_HZVhi+eB**N z+9&Ng74$JWh4hi-K7ZBR6xoqeR{KuZxIK0E+RIJ49{80-nVMJoZhc?a}Y!%HT{RU;fmY#(OE~ z226nWLujU2`GG`-FITs#F7-VGf7b_s^rM65jU2Ns;^nY-5%HY&Mxxx4?(*=wnfBwO z`EZiBccQSIzNgz*#GBajugm|+v-D4we`u@NSLRq_t7Y55d#m%CgN-CQyHE9pdjZnO zkB3f9rMeHg9oQ2dUL3bHw*%Cr%t==OT+$zF(heLwi$oH3G+G6gJ8Ss5c}jW9e-k{I zZ<=hgc`FJc$eU}McQ|=LQe^LihWFTWi}4K3CEn=W%AejEnmgY_L#?grz4+L2qP)hU zU6yn=U*f47AE29#8R!W$aDrO@i9XOUn+VK448i4X0pAzg{iU;K(A4k$>7BVc)RtY2 z8t?Y5Vb_!MomQVrdh=RpVB0&cT>D+K{*8uzxD#P>+(y=nW5*2uqE1@(Zii+BV-@mx z-88{3AbabFE8=?n#Ms*fs;A2hf-i^f*pjmgN_`6_7Zo_*>}P%3ZY+V4nL`c(>K>mD zSh#7o3pWnK>8b`?WtYt#mhb}6hR^PUK>N`x9#?Vjx{_r4rUPolgOmOYz*An-;h&#X zHwk+TE}R2%tS{HcWHvCjyKpz$^XOi6uX7*WHFrO_PcI!W9l7riFSu`(%yOMbhHKbn z{@}&cnX5Y$fs0-h5ZM}Go?CX}T;PtiBKPSNp3ISLOTJ+$yIgc;$lTlB^7hZ`6!~n` zi|dXYyE9OkpI9u{ank^thPQL?VcqpqK&UUe^J0UQ-r`fT(^xkU+=596lR38&n$*6| zG$pw8B)=u{(<0%)ts4fyTilIyJ-**X;3it}$yygU5NhU|2hLJQ)2hcPIy=(k>PjSy zK5LMpFbqKM6h%c#jg#G9u3W5&d?$Vzbs;6$kw4L4OLW!XROW;XDXiNQmRN;EIwpz+ zqoJ?R2d>iHY}*Dj4W?u%7G~a%mf9GHMvY$x;=^ahy#Uh-O;`3G- zXsJQ!1Dyg5G^cr!DAZiTx|LAgG((fw1WgoyL9JVGE81qb7f_4nr;VIOY|1bpa5*dS zCWU{_l36zX`b4?Vg-vmIY{!G{x=iioh4$ zDH2T~EbJO3J#Zms1dHe8CE8DiU z^W4|9wR1m{AxtoqNOFue+F$D~pU%NTa7A%x#BCXFKpzn2ve{j|PvSXf}5k=i;HBZFM7ep^6pwxi^am*pCHbwGTeH}?}+^Eknq*5FY^4? zT9~!#%lq3dSf}LSi?v?v4#?(PU+$LrU9I|y)~33cYo8bG?yM2tIf}%hj=e`kr{lZt z%gg0sBFs;V-=5x=-gg@0IVCk(ubgFWO3K~KTC*!W@4BeYM5!?e{h9ktsHoJtJk4Ec<)4MAIQ9px5nvSVPWH^vO- zccA_A5)%)-ReCGlvk)gZubp}WkIsdhnkU!iFwC?YmqtB-acSlr8}t$dcgejM_o{n_ zxcfxSx--QEogTPv-xcX2cS~#d>dd_~zy){zChtP-^vEKq(dc}TNBz>*A@k!)o4idQ zmAOx~3_;vicc<|l1H4O-TpcnZ@4ZoZGbck1LH>Y)C9n1P2H|~kQAuOx@?h9kHMKM} z;U;C!x*GrtM)}=4h4iG7s@~NzmeCI`eqRQsJ~7>BHEz*+6!PVK!{@`tT_>Z2wBR&U z-57yU)cb&c4;-Aj#{4%+*Kjv2H}o`ZcuvEucp4^;LP;*%UhTSrQ_QuV!wfXu72rU^ zCU1&&Hb6@Wp`ne62L`DSYiS7e6l>oxnxy^XC?5QKjH>7fgpJ>p1wGu!ME5mN%H0f1 z28@ZyJl;ld;ZYtKB@oxL^;~hhQ4R;=7@aDnATW{~I zKC5QQcu|3f;++PZ%l+hxj1x_tCBN!ungAxAS;E=9sqwd>McY1R)VT+J* z$XxQ2lqZe3_J~I%XhtvG;bda`xPb1+;vqyGIX!q7gT3##LyQ>6%PqF`2u6HQ7=O26 z_$CGRjIfLM@G9TySNeZ_vm`p60rda>OiBt7a;+GAsPUWawE}g>QtT`o9R6`SzoEu* zP&^$FYxtNaz+_w%l^*LxV7br0lrPrfr20~?6Z?3$`V5>urStv^Dpup{D={K3fCC2| zcyn%Ea!S2xD0_37?R!0L;f*Yzq!BL_eQgZkRRJgCtqP0CowM+qPWP;K`~IGLNAGWX z9^U**@ArT|-io8=M#=w87Jm00uGCtjHy>LFCd%sa)TSJdL{XN4@MuyRA zZs@keJ2wT;tdj3>Jznk&nyh=nK|c%f@wyvI{^mI?SsnA=587GAoZ-6gh?cu}4RgMQ z66V6jD&!(1Y@7^gh??C(oxoUEr7W)E`EmAaO;2zJ zi(VbR!KnY+fBe_wm$K^&r|-44wXNZuCnPym$MLN#tvfrb{cNzSNxXX;6mbN}F|6S+ z>`9;0<x1Ap0IupZWJKQkr1E9~ zSnpj!**h%xT91eD9`D{tdJ3^&pI{-cx7;xZ;*uCLzi0-+d1Lnph4ikHW|CX5`PyV# z!@Kto-P@^Ux+jWWm+VFFtB^-Q=j|rbpsm*Z1kO=)9lrbV^nUQ~3x}&~_TP&0jJs>O zPmdcp8t&pX%y~m87w_+n-Xq=LnCo6*hO_(uL5uo#_Qwei{{BYXGNt6?^K`sh5ihM5^{}YH+#_hSJ2yh+8)d)Ju@XLJ4URt=zXVI( zM91#N`7+SAG}r?QQ$0zpWY!?S^jlSQ706F6L}JYBZrWQH@5$JT1|SK;H8V{coHt1F zEdV-|{~hfa-)2Q{cOe;drV@K752E__!MdTQDA_o-S2zw8**C zU6SQ|lFQZ6uLLr3H=aH! zot=c{@eGwV?TYAPeBSW({yyFL&m{Z4Wjk{n{xttA{2U>fGPQr@=k31s$)y|N=WZ7c zVK~ajDQ7Oi;Tr0#C*X&Q6iSa(BQ-IB69!%kG!y92w;s;N0$OG;lID)6fD}WI+MEXe z7%0UbQ*cX-6Ft`4V6at>GgPq8(Ag$C(8XgL9}y65ukoZr;=@BCBccw4LKLX);IOr* zvN_vAhe(hj{EfbmgxsS`jv5hhF1>gSya?^;7Cr;}KsCq)NbY^i*3s{*;eSM>#dng& z+gy(9a8>u4PORe@)PMZ^7tAifyCju}w;K!^3kcZZ{00#Ry{2zmw9qH6>aZ4m?qQVM zL^{s$AwFuk8k^DSXEh%pTkB9Hhfxh#Ri9|1DrU4|lM-4O$nPm%oO8h?TB}Hm^HAN@15P*HAS5woJ44 z74jh)0_aQq2WkDtu8V5f5N!aCY`WudXq!IVfHK@(3WX>hrIyu)CEu4|Srsbx? zKQQI~Y1QRNXLl|=ii2@SeLJey z(B~SSAJ-Wr`A`3<{MQAeA7+`(x|MY;1$%LL))-nO>-1*l_d#LKn-NRz83o;Uk10NC zFGh%y9D?NR>em+PhVdz_jJdMf!H|PXxEA~H(yWs=t*koAvYM8PUl@PJvx5i^$#Xw0 zU@l%qqv5eO#5LTN0WS@`+y#Om@NwWdaK1}@ukIrPIKW;FmWSYWXV(ML z^4l`a>&z6`0VmX$-)y^`hJzlDoqGh@#%a7%6d!&jNh4yp)znm)b3dLxFyZdXUrorN87^+Lb+*6;#^xqjmAr(Q-9G zmJxHIxq(`bYCNa-Q52FK`pLbJ){B|x!2QG>VUT7q zjonkRN!nW^(1F>@6ySi6Ywob&H2RgIF8eCEglga}$9+wbIbV}t({-Li2OStkQ`wh@ zz63A%-=lD$_i3#WpZ1@`GZlN$`?Jcy$d5t3LH=@dd)<46X{29em~%>NY&veo3RDYb z`*-!eHF9~k;n?;Vp$RgC>1u&KGIU3rq4z1%O-DXp%r%4^ytnY+pwUQT6jA=tehoOZ zN`pGd3BC{5w#^Q41A-w4FKybnt(!vzqo62D4&(}fqFg-b=4MA59EHr}x8O*Hq`Z-! zRj}2hG8{SUUR74lwi0}FZ4-&7!Ly9qE`hWs6n%$n4s!B= zsb4x@viFG>{!KMf0zcS4AgcLQ5RU_W#+98X#Y7=3z5TzbKTlw}4wC1Y-><+|eGbk$ z7!S7ugfy6<>464b7ivG03<|=?DOjGU!;Uqani{YVX^SR_K8-vz)X5d|w65rO(^9&x zM3};$xhLhEjzg8!*mT@3D^Ni#2mf5^#=&&Uh5?7_M#gQ!+>19ix~rKnWUh>kaj82R zwz-I>K8F+_0;|-0mqFRyEp@*pkUxZz@IDD5!nch6S;=)ggMaw>Pydy6Zl-S|4_n;Y z;_KFN*+9ae5{dFABUgvE7_*hrGK_mI&-49~4XDkzYz0||t@m4T@;BfH(h4$~=YC>1 zuQJFUzp-SuBM-^^hhy?vMD>bjRSOS?q;2-IVa6PJPK~p78uIR4PTC{iYXCcX=j1kq zutzaNf_LWo#Lkl0?S0R4GtzzI)o+x&5W~2)h^)>{q}2GBc`iSn!T zw?9t)MUMaQ^v`s@2s+zC+w{}vjGmxAgfe+V>YDCd;CD4U9aG{I%$}~U|KzOs(|b;6 zUzu(?@`W+icU?^0TXtJUAB|k2ETh}olsFC>YEm$0y^UU*YJo6>@H4c%Jrtx9-emaF z9JN51K){D7-@#e;Gk6&U&nsI~aF|&S1q`2=a357WNV%K^d*Ag+Dd;kIcmL~u`_KO+ zd24@Z{Rg&IVqOS}b8qQtO->$8Ww*_K4UakUoEop* zIj;>~fXfI=e2>h3+A8E5MxK-q?DWN}(e0z&Z^L{@e~@9AoYESbj$5(vN)+FV0BAs$ zzuqaZ<)>rd$9HR(7pX6U>+0Y@{C$ffUwXeW-8%AvG0zBl@!sIY=+nqGN|b-**P8E1 z>V!M>cpGT2U5GCbh7dk8?X&A37KXcBX`1{}9z{{jk z0&&1x^6tE+kKB6Cgj;Z|qbr#{Df5DX#lHA<39;V=`~W9Tf37(8S=NH;&|bWYQ8TZ# z99CqLR#%4oIF8opgvL7{)pxIsy+63mxC0FDm(jV0rCXK_Ef${E@}Gx^#1p#lCfgjj zi|4pnaOXVq!>I_UF&~GN>H4-e$lW(`8VS=SW&;RK{nbm1bkD9_&B;ka=;leM&WH#V zxTn!{mEfgQ4t!6uk?<`e`J#6Z(L?W@Ts02*Yk3p{rWbp?6t5MTdcT+=r2;5A`~4c- zMejnAQ_qN}aJP-`@CdU!t8PfI!vceV2X-+uv#ojRkZ*YSnx})c-mOCuGaWVs$uKn1 zEhzO|f88;Kz=pcelG7S%?eGBr!O593LQRKY0grAvqAb9q;0F|aIA4mPHu8}Ic2`%1 zduNGMepiOqXWgmRRY6DHYCofIT3@5SmQkx2kXw$9rRA z6>)KZGS@QDoyU+m50xKZxe0j9rIEsjnnePmu8ehMlz?yuf(~t?P`kRE)Ank1QuBJ0 z^dW^(@p5R@J|HEiB*pajb2#8wIYxnB z!*!DsDN1l=feaDHqj*ei{y)n84bW^_*}E}ZthPbA8iT72L}=|3Aos9>=jm$5|9T8a`gk_NJ3-4gyt||GNc=3WZO2Cy zF#N?e?vXfmu*z*trU>l#{TLnw{vR$u&XN2H-d)k&T>fxmMEn@g19DIALXW*~hw7b0 z{fGV4N6F#cpJlwvzd0YbHt=sQPV~!72d6F$S!_K(<%A74pWvRSv^knBX2E{XZeCj4 zwp~(OQ`=;sW4<^)RY*M}OiAo1Xp{S00z9zOiB-7RNbj(mp)9246RiA@B7a z_ojDscjvwRNC8%#fQt{1D)JI0TfF{Lh3JV(W!u-W^@vGY5kL9^t9|L^_VfB#>S zw}0ecd+mpXaK6-QY5Usn-@75dG1kaTh9aQ?A8OV1MSMn|HidWqAH0lfL3?v%(jg6o zf|1-^_;yf3z0mVYl#zWl|}*ysSAI^V+Ci84s_27IrltFP5LEirxk zG}677cc-o{=sd&7c)Cd7@0g|L;r8`&MG6#enS!ZI!Oqs#sHBVDPasKh2ggM?IBdMa zBWC%lIw#b4?=bsf7blzT?5UT0r{im{$5i`C1*YRuLH3vuly{YSf^PrX7G5g&wB%aj zcE=q6!8zu9QPX_IkR72*q|aCIXCfZmeY5xOD+O%fahsTJM1|jH;riw-S}z+P*Zh6y zjVE^)`zsr-t98dAG14SZoCYK`(svF}I$lBo{}?Ue6Q<&cVvhXvxswEIWqdGOq|n}A zuwjfWmliP-PX(z<*<{vb-(Ax(v%PQbH15z~8%Qm{FF~4mo!px+yoTcRK~)uy)b?QL8wBv|;Q?g*dC{n!QzT|%9j`8fkoq!>5dy7!f za9`q1oBc`&-Ymq)U5X>Xdkaokt9?J|0jZE!1b!e4F%uW* zNKZ;;K;~L^mI}Fp8c&fya?mCLfHF$>1aM`L^t z1~ufi%JT~0q=VdAdu3D(W9041c$WpBHWO<@GKfHW`;lGw=$kOm#3fW^Lo<>%#{_&b z44yYUSk40_{6ipS+&S3i<{Y%sx^UkKi1!Fk7lMcb-LnmN`=16sKR|MQ`wzN5DEpLme@$}x|@~((NNv?M?Wc+AI)8~_qPstbM*hM)0+RHb5ocxPh z|J9fI)ZBq+jAc`e%XoWzZs~F9@USRJ@am=7gEx=ufZ^D9X=>m>P*cQPNCz6-vJ5w{ z2(?nuhOz_Kd^eXGX&)w>LOk_Z+mvjB+*T1^g7!U%Bn`B;hCMl@(276wdV24#`vFGM z;lJ@^bl-f0;2RY$iDtfhP$QOg@Ax88*sgtFMCC`O*unnB^;i)0M<-h?AksYRdcRbC0b%9PNAgBlR z@lR;-S}2Km5ZQ+D^^B6DLdAf^{w7gZ@XDOMLRk&tzA5$9hukx0faiO7#eH;EI3>4j z>EUmw0Casv(-|jH++j z*m_4bFM^xJ^-xquUuAg|aZ_%+zl&4OY2SbJKq?YP;AfYO9JdD2m281L?cJ)#J!<^E z2075)8usLr;x01U8%(Cpq5^GU5Bip9i>s5yu=mg0mr>gqUEp@%`LW}Di{tYEZ*^qy zc2{C@(hlW~Xq^lQ-l#ltTm#Ps{JY}pa;{(g@Cm9A+wZwY3wI;qj zvdn-cVL$B0ng4UW}a^Q*Oi)BXXR zRd#W@Da36gJ*V(>exi|`u*a>-(FcM~o_2dUGK@2^YGe@W9pKdW8v%^IawfN$!-1=Q z{G4ovNCkEr9iw}oG(z6Jc@1>T`p2TyI}2A zOmOx07i%ulaP*Dzo#*7mmnWbK89G%9w0JG=&vN=Md6XRf+W-6i|IU5G4-MuD*WB9t zzM!E4n0O9-$a@!$*nVp~ThrBsdCU-!-8f_cr>3;Slj{pFQZipoPit6QvAAvty?##D zyb=AX?jnIR47QY}wB^IUgdz1R_?NNu^C7~`tYF{mH!@@F`#RX+jFP~|>)`|uk|l2* z4!0y{=CTWbVsGbOI}(2WcmMVu^!EP7v-v|pKUO)*-pXEMk-C?ycaBm*`JFvsW3bH} z>Q~sd^lTBNvCh#-&ts2wF=HBdgs|+AYH@E6)i!NQ|=}0#r)^ zI}+J>P6RMSfs0w+ss$&u9kk7iYuVwCWd4xT#wFk} zyH`hBM~Z8p2}~Vv@vll@R$8*$Kd~8VoC`CC--!|nMDp_ZumMYrreDe-lCw(!g^5pHFoZ- z$n@LQ7lE`gQ>mH2^k}9-v(<-mE634A0FBo*(|G7SDzF)MUQ(ZB!AFHAFz32iQmB?> zyUCiLZM(D;Sr8&#Wd$m*93ABj!yOVZy|}+erS9(e(Y=Zy?u<b+OJ zKXdKg#Xk>VRi;)(8(cHbNpMS6hf-1naVL^auh9s54S(DlB0N$NTp0+DS0>(~ei@TA zol={;6EFZnG{^RP)|8nCUnsTW=SJOg=y)r#sC_AjNbIO#b24e&1<|NG+;W8FX5DG_ zE5@XGR&fu@P9M%&B2f;^3e}Jtkl;}+N7f2usS=I2XmHEc3tJVA$2#vV4wW@Hg-ipr zsamSR(@*^Fq5V+6cL=VBYmW?x@WnGZ9f0_L7KO{hVA+lK*~UExpk!>7teBIu>f6jkkR`(HzN@dZexi!>#gOm8%z22c__Ynim;Q z@2nbRu0!Vhib`%Bo}PK`fiS50mR@$VC{*xf-SOcuKs!8shoJ4Jgqs9}N4^i9!9Z}o-%%K-Mj66Pu-}8r zK_;?yxqQies>%ZHO|6*1eewVhxrQWLe)Ijue+x_&ueVzjNfW2TB94`#RluWR+frJ| zP^1oJAngX&4Vv5aQ7BLTYa!m8q-~6J(_cRgDj)fDWm$M9ZvW(hJg{L)t=^f8K57G~i zVf){6($jzKJ>NdEF1$-}=ki}HJZd~^o!FmW+F@RK0Yt!)+)CuH-5)21UyYZ(7tQ;* zpZh&}?EH|7Nt}DSJK~hT)|w@j(Yo%Xg62`x$eYK+_MK(6gVzH5neS3+lUG!)#%#n<2iaS!B&cknK+W2-cS0Y3a{VHl^2%1+=x0I z9)Ge@3EE%|PJZLPqRv;nYqgX|mbnTdw*St*DF21w?@wvJ^lP_TD))-DwbDv~8jo)! zXLiH@Bjy7rXtLo*I>sh8ogs1gbn`8&Mz~_T>GH_)HDER;rsVzaL+t1pOW#5QmTU7L;`qz2z!k`{*>W-RW-J_i0?eJ zBjt6vZOqcVhYHFNjcv5sQqp_OJbY7i@z2uxLC0^AtM(JjA$YD@eSh}e&k{4s?ib5# z@0$I`m@@E!dnmg++min$Y2Pmxe53Vh<7d#9)oQEn+t8J#!y>LWATBXjni^VYjHWU53QFn2g3%Vo z@YuN2X%RRJsKAf+Q&NAhOr|Dj>uK=cWe8C+fY^7NZtV*K%c_xhaOps#+U|XG$7Fm` zUfmfzbdPsWXFUrIuE2y5b$|)ENKD&5BYxk0aA&j@EXDm6v)aA=>gbq-zLL1b;J8_M2xy7FR_~5;1hi4t z4a-eX(q7`|+>zF1zxRg|EE(oob;RlC7nM`y0rCR%h+`#{H#hh=#*=uX^v;3wHd628 z1AFLQ2%73!ULltxabv-SFDSjdp1$anbe!X2C#5*&L81pm^du zXKkR@E51(Z44-bQX@GzjLL4|isw%4TRQsrlC98$pcvW6map_@#$@wVU_nLv;Y{W~OVfDu2=3T%+b+|<*vsRBH{{wO|0i*O=lt+Zb zX%tPYg!|J-qWuhXe^Al=bdvWlknr=o0!5;^Qkwna6~Ap!TBwAfc0rZ`#-Z@WSH9n6`RL4r-@&A7!tb64a_0#cp1}4f7#s$A<;vMO zF`x|8-hn~go8+fq81A8y!Ht z=k)i2*3oOLqPE|%;Wq?(p9$pVjA~-q`^2tlOYF_O_s*5yc+*sz>b(ZvHyIb^yNnsF z-AH$2xc_i~B~PsP8y#LP?&AS%B+7jJGp>Ccp2-*@2Y;k^eA5#bJb_LB)Bdzq-u5Ut zT)tOf3hsP|;?~yxO)RIKmNW?i;&ROm!R|uCB_Gb;hpY`OB<|a)2V{F9k-2=b({6HsH{@v$h-b`s44VXMFmq zrWFF|FpeTfLl$JGSv13`ytd($SWXgm~47!Tvrt22TLxokLD|^Weh8?QamuJIha7IW3i-V)rukS z%L1>@m|g&qME90lD=awn;8b5!HwLNB!l*X53qYR-()0Y?!|jF$bpr>`$Pu^_BZ#MA7ZQalfg$A2TqN zQ|SGU;=AMmo6L5fu0SNBqF=63j$ld#{jD9`bltV;o}})U%nk{wkW*|k*kF)Zcd_#D z$f&zS4OX2Q4f`(IT&`!-9dwZ0DWaKNY7=SyslTI)SAqiQP$e|{s<@%bC0#=-Cw>p8 zVgL9Y@%=so;X4KI#H4^6=L9eHcEg^fAu7HJkY_4_Kzz>u`+Zi&eWH=7;POC5ekS^; zLt4p%doaE#ejiA-Z!Z_$3!q2JjW~_(dr}k>V-s3SfHl2V%+fhg19jKg43xPMC_K;` z#wjMIV#s)Lf{2BDa_6op%_uSSm4KshCH}Qg(6~p{ZmWKUVw;%eFr2-1Sc7{T@*FX& zFtpXdjEl@ZXI(-*lpwv_(y@JjW?OpR89JN~sz3zD8U}|!-PH{X*%$6 zPhJvd;T_^~7~&4dTn3Dz5h6tj_ykQQYnr5WBqWuA_vVBOAiohNe;-J;<+nfnvWF9- z4g0fzYitTOjvF)m+eT~6(9OC_`jG$>a(Bbuq~yTlG+a|5XtrG)xXu@^9TZVCLp3w- ziu&lz!HFnR?vJ;lcK5jYfc2-Bbvrah^}Q9?uI0lV`lDV~+H1yRR(}+ryrr?1!X7yP z?UNIwy!6`#xd41MPaYM>Q6F4CxlUUqS$Ip^_wwIXJONDC&$pE9M=9dL$r*Q!BiFu* zd7y|!u^uMO2lf2Z=wGpa;A7-1U+^2g39HUsIz>6Wc6e#aJsj;3f@G2FS5@z7V)mh>1*{*OVDE|Ly#qupsCCbiBd>b+ zZ~pE7@Gr>Q@9=+&pRKKD-OsI7obK%K=KMkSg(kYi#k~I_pTHKg{oPg&l2GB7=cEsU zl??se1-Gty@7-UGAKzs5Bzz`kZ1b?`%k4c@zUmslNcK;U3w;kZ&+V4nQ3ve)$vEb& z9oz8I^~@_FfQ~AG@OO-fggx$FL=NALnp@A`5%rx!U37DE!Yjx1p$^Pl|Z}|{8@^>CYJ&y(tfa0DicQq*iFm3 zU7=kWUOAkDy-3uNeRfo-m}6Jmb@G33pStt0Kpxz$rSvEFl6zFojJg$qI9H9gz@5~B z{N24T?mFS)gZo|8vPWF>$>Z14vs>S*02A=H$|6o5o5r%w{gPX+ zz>#n9^f;uHd@^e`*_6r_TDGk$Y&N#7iEORNS17g;G+Tqqi<6guPQy`rVUX)#3#HzE z96dRuaiRf@N-CEM|gft>H(|7tLMo3MP0<-C@38h>JliEwX0*KSK- z+fdC&5+&YX;Xvh{NJZOPfHvd!Y$A_GsNut*icg%s%<>^IjxOaAC?6?iyq;qKBzRx1G!SH9h+gqU*DX}Ofg-XrCK z2w0Xy?$=g4srMw=9;WvB`1Z20cY|cu|Kq>?C+^|)`x(#XpY2-OR$AG%y{+rkUTB5Q z*yyuP>@|h6*VHrV&9S?Kk**s!RONsag)Q>{EW_mZ5ZayLa8v+y0HeR{9OUy%DXDz~=kL9c2=G z6KR!8O%#2^8$V3$xe7O5u?M^6XYR54kW&vBn!%6W%Rw`cGDln&0gPCptyZ(ZWwz6Y zi5vn2JgS61J!A&%5F%j}l{`P& z>F!Yf4hhB2128wH2iC@J0jo@lW@qiM>+gOxY_=}UrD{TP@WrTl0qfoyy|W#-(oT5q z-1}%#(RlWplPZ_oLuTDUrmq}mTU-yR9t==oJSUoO8hnAxStTMT2zj;KF{&D`D!BNZ zfhwb}l*xRTs4o`@O+IRRcxTg7OWiAIatj1*_)xA_?`tSst=z{ z1&~}LLkM|Oy}l2cz(|gCib1_!&6Jz zU9@`Jb~nDAqRfr*h~KAO38*-=C!xF^pEN`4AC zzGpd<5{(z!5@t$%_orlbCY*PjDXmC(Ew~Nw@shk3ZqK zY$T+_NfsG&UpuMW57slBgaSa-fq4}*50ZDe8a-GCpqqb!D**tGD`^1i8X2IjQEiP- z+t{Bl<3yG`56!L6&&pXg{vk7Ud61uFi;wNJCANy1-4m*PKb1PW4I^UiW#1WCW*bHL za7suEu&XigAn{RzxAabx&pGg4=hiXfMx~hM?u>9= zyGF75zXVV-=F6P)%wEVuW_^OF1@$9T@jJ)8Jqh=HbrkZ)`)6*O$PRg9xye~Io~1;N zf!@~Zav$yeygVo*`J(BY3AgVqz4P$~f#87HW%vWP<&#cg_YPCPNSv=Bv!Bra;XnSj zczZwN+5EGewcspj*K+d6d#lFdW-B*Gt>Ng}1P}z=H5E7AIGsDRJC5x}k{u+L<YeMrllJ1h_uhZfJJEdeEvNFkmFV=9>WgG|N1eg;-Rj|hlI5>wJ00b; zRO~;(+PoFnbRPU>dPNt)hDKhU9bNhNjCRE*9uqadoVwr-jeUL z$P&CalHuda{e|o!)$|9{Q^4EoK>sy`i=o=S)M`kXfv*D2RyLUw)5vvPM z5A55w3O0h>JNMiHh9PvvF!856(c^G=JoS#JNF^v-r_Pa@>|27yB|eE45^wqQAHN;y z{RT9bbQ@vUSV~DIkJ!5fl}j_CupJU@{9Qi^32*q#1Wa zX<u?Tf2Bi2q_-!JfysNp}vEMaWA(B z>(57W{DW;Q_Vx1gQEs4;pf`_bSDYs%9{kz-BEBsxx}9u49(1Oo8f+C zgdQZI1R_gsdr3lF9;ptIUuMWt0np*$|9}7XpZ<$~HQv5j`I`ScpZ4b3$`(t%P`5hN zh7G$7RZi_KfZ^3l>1;}CE-y-TaRc{u$-{RIgi=!c8@AXyz8g4k%6jW^R>vkNU4A^p zA}QfbGabx!g{m#yQ5&HaWN`fg_(;Nl9vRO-9uRNSo`d3%>!QLpA^B*5YhWpM=8qH} zzb~VVGql-~-Wh3`ZhHHzcfa(0*JfYy(!qG9clq?c1L5z>ff3&WEjR6UeWW;qJ4z4q zjx}F+(z{+eSU0`n%<;)yzVyCH>6--IfoHX?IDcSK)<5a}#OzyIbUWE9pznG2??~|#|Nd<4@j`Icc z{8skqme3j;_Jm*yYeg3Z(RNa)>9u+gR^`M5-fl=v0u^yYDs?La%^y)Y^5UgusZSmRzqm-$~uZv$l9Yutf^+(EUp z)0p^v`JfWOP=A)$(5>{ufQHBn-^iV5S)^4GjdCMn(9e$*Tl8t-z6~9@IXZegXl_Kl zn!EEnAPL;%)4$~OIN+DwETnsn)7fm7eN~D*Ca0fPmkmSimK{hjgX-5&*~xPI5_K=# zw$@W-1prm@gF&A3Yvx?iKL+YuDR1-5p7Pi(PpD@l9QNc*Ql8x1_PM3xL+}DgVW%av z_TXd)31A_a36P}DK{r!F$6T7QBlWcOMN^m?LYj@#Nw-MEbi|SL(zb1lP@-JODAf*< z*$~`(143z;=1MMV$#65d+!sj^<`tpXfh~0xZ=MHGH&r%t1iud+#P-DbRudRbAb$8P z=cV99eJcZjTA}6xs%3DfS%AXFRjHE!l|u-*0)$n06WYP88k+8B+HuEqR)QK9Tf*96JhKA8 z&iRV!VYs@`dgjL!WwgPOl(!+;DyNLz{6-ZhhN6PbPAS~)ao zQ&JlZ;7TG=nuq}MYiOs4ILCY>pyLj-07J{2T~5Lsp21!7JY}JL59oo&z%6L{BgjXe zn!M$I49HWro8%%i2{_!7_>{z3{{F`wg%R6{!Zw4pLh9keYEtnQ3d{u#hlT^(6p61} zx~=4&2x?hTHdKL|Gy5b@i)JN$A$OnPoO)?#e&yJio!RYp8h!)(2E)>Ta7J>z-FIdwtK!T*`H}`%r-y z%ZjpJ3vrL$?^$#kT36oA^!EV*;eurEKEi(Eu(CE*`?1QI10Se+bbd8+SY9;J%wRd zS#vh%Y{5`+qONDo(U!-FpCtYMxBu~fo45BX{%*fZTg%=`Ti1PEYiVWQHu} z0tZ7PmVpL8egptaI6&yk0oZlISVNoByhAJ((1d7o$?Nj32#3SChHUsk$s1%m9D9Q1 zCbA}?+(}f2=K|nm<Ic=R z?v~p(s5$w3Ka25ZeEwUaMACPCj@s$`<JqjJ9fnT7xYw z-VC6RUyR%h21dTFg6C{V^T(uaPE-uwHW?bhN5y@zUFvw;aW&ApF$zw@@- zT(hC~y)mZ_#H>1s?t8-K-RFjb=_VDGa(_%P!V24hC<_1?1OblZz$1^|?;fCZ@;@x^U(o6R8vwP<(%N?}bXePb%ywJn4Iu6p`1py0eYOZP@k1a^wsS>n%!Mq9>!^ z>=dV<)}Cw~5FEN*?++xLJ=A&NW8E1eH|n0tv$g3Vp%hh&W}h_`wLmEt3^%escUM&i zLCJ1uYwr`v=7(@4k<{-VVISE4;5l>f6?=d`faK|1o+Qtf0I4T-)05QiTo2tMNy^xT zLv~Mg(jVRD<|I3$`~LJj3AnuJywD(Mfi+vbRg)u$25%FDJ!>bkY7^Kls4%trqloia z6Kf=7$l+oFY(aud4sx66Y1BcH?IJyY+XGK5_+!vq^H1cn&5A)`h+bZn^ zb(bNi;{l=(K!i-&N`;^q6l-PF-RSkUTC;ZrPlR)$NarINnvHs7HWN_kM1Tvx?}E>R zG^FgpDD=B0vKtebi0v5#<|D4Z19~9B3C(Yk*9BUWs3lIC>Un)T-jjICPd|PQbiSm2 zNNxaRF4IHui2IxP*N8OB19Xhth$y}-*w(!!Mx4(woSDt3&O$88x~!`wcr zb}kut_RDWXEaT1u%&0N)RN!suA+z~lmuv()^XolExg#Fj@?Q?UL^!ke@v!YEG{CU+ zn@dDsxMNT|w0+xq#=h4OGR4NbWqq?rNC_0dzm&X#-7)4^{jz>?r!Q|wt{mr^aPT8Y z`$E0;>(9(z@V1v98$T@gB0F{h*C(%Zp&3p-f*p@*m*5T*C~&BEN_K%=dhHkU&_JzK zM>cl7M5yLJ2zl6V`1orut@^!wtx3=c+&BcgqP@1A+a@&X`7d{OQo#E10cMQ+q$Uy+ z&Dm`Q{p(Ej!_=SjGb0v;%%QDoHWW;Hu>s6sA1gy z(Y=sQd zO)4m5Ju09tD#W$YDGLA@rGbV)W1J0{c%5cA2)kcrAfv!*YOTT|valMm3P zEQ?7KjvR?Mt@hwlUo}In#T(mrCs79o&~b{!am+TD)Z4u`_ukwkM#W^8R~96O=rMc$ z#9aq+AXdqJ#U0nUC+_t{nAiyip&#t5N3YETN#)kd)WMi@J^GGLTfn88#l7Lz;khg$ zQ(dc|tunbE%Kn0BUUPEq6yFbxHKBL>=-!9rxFp!XK%UL_rpz|gp95F%L zAb{z)pV+d>@Z(@qq1R54AB65gxHH8b zbNA4@r>_YNwx92(z*i}759Ef8dG#5mIrHhcA>wd_2%vs|nODD6Q7e>Eqesf@tml;X+_Mc==s5S8UEr z)0$$`Mm-L)9fbwzE7aDUWTK!p3vC@^N?Nk=MjV=OsUNDX&R#=p6J8jN9XTR(k^b}T z5Kr2>rN3IFKI=i@E><25K?gpCU>&VNzXK=-?N5Pe5NnP>+|pW!y`Mtz?t3ntJtB}j z9+bzOOc^q6)6P?XGw9xID2@33^#7H3%WuB_4;Z#Q+v2cV1eXk2y|rV;rUhK~Yfxq< z-&>h5#2YQAXPZM%SH_NH6xp6QeuzZk<)vlm<+Mi|Q#|thVl4@L{_e+*FSWUNpU4hv zv*kH^LVuRk3*oAFN^18$6z^uWtcD}MCq}E6efEbfz5^MSnRaCRY@-V|R@m0dXGQUv z^U^TN?ZkL`AF}<{yUWh?ItETBZ&Qz3`!&9#J>vuh^*3+*_UrlgxV+)x9v6#`9be>p zzTNw+pZh5;PC|s%vL%NvA@toeT*wTL%Y&mDn&U32 zpqr;*XeFyzZHHgWnDyZ`Wmjw+#Xe=4C7s<6vTsy;?5ZzI*!1ia?`E~Eh9ma(n1mwhzDjzxl2PeyEzJFS4QrkW+ zSmem|FVdW!_0uJWmD#x7TY%6j&6g)5JG2r4_`T88X+x~2ebdmpfvTI0a$ZN=O&h!3 zYPLU%XK$5#Vll#wCEti^2MJ}>IkCQidK9EiUMDuckrX3_<4X=ebFe#PJd9nRy8&&2 zG9nE{nuLD6w>b}WR813ouiSOzOle50&-{GfuH{$PL<1_3!ViZi%%jK(SOL&PKi$_ z_ix4Jp_-LhatCbMJGaII-t%p-AeTZ)3+J z=sYEp;H+cVFqj>B2lw`u;#|@D2B3poE}VBa<31qy=!mc2FI@nI;O40GQ~Z?9LqG%v z4)9A*{Yb`=yzr0M``~-0- z@FB)#i%{*%LqL>o7+ItTv?=)}eh((srXC3Zc8A=3Qv<10y1MZ{>DW7?BOay}4lGUI zCfNLd1d21rZZtSSbnHjfl5W2XmZ`mx5%$L-?CU{8*q&k3%?fLb#-}1%zrq z)B{CFA)%EA2+X(9bbbK2XvwX0Lmmj->Q<+^)NWf!g2wFa16=(h?X@8D0*nj(?Swgj zFgL&>3ehE`eMvxr!{mqK%P## z6&pyjCJ;UKA( z`AS8no8JBxR&{Cd31jZCn_=!tw&B*1(PKsS9gB=KXO3~?i}NP;>D@QO{DOd!hj8@X z>G5kkhQH}Z4K#(5M%d52zxYe|=jYqu8$2S;bNLjPal?80?SAcP-RtC|(~x&P`F=CJ zkMJMcMP4DB(pjU=0te3XSBlhsl5u%v>q{q&;j%=}3_v-jthe01U~_*ig*A|)aS@~C% zl77v=$H0_B5L1;I!Wo1%Fb8SK)kl_1JjTi%97SZN$6~9sPnw=fEA5U*n5J*;b?$ZU zqdS7B``|L5t!rLBd_)dhUY?DDpygu_66A*nO10`h=`8Mb(&V#yNl7=J2)@?eHFq2O zt))9)g;nMmBntw_zl65v-t>wgFK{n#RI}vH^D(IGwCATk{c6>_ZGSZMx7DCEavduL z#DuYNMKhqbOnI?FMKIZ+_i%X9(?H8d1AC9Eo|DvKcqzU(4G_yVlqKJMtIJf8x*tYchwL3te7~v=d z93ig&*Z@dCx4*YX5TbSb6n;m<55obzE<(odxQ2eWB?>3BzR4obxfe?jiey{ZR6Bck zStB6RpzAt*b|Kn`0Wl2S0?6HohZ0M<_^s_~EKxUv#8WE$*1fE>S8<@%(60+R}^-h$lo(~s}q#b7ydT-pBPC`(9h6hG`X z8mQihYHhx>_(;;ShJTNtcQSiCz%Z@)yfJDWUvnW7uCu+@sRN8HKY*@`f>+#KSmYa1 z<(scPUvB^Fr~QV1-{axyseh5)`>nrp?mcba_RNn4$w}%ku|2s$hr!@^Cug;7zJIgX zqJogNH~)l?-h2kDnd8~Cn~gfYU?klM_RF;|RtsOsb1Qj9v6GZ=i(Q9Ik1rTzT)eYc z`5kDJ-jVWGEj~3z$K&wRyA}!$8M_-_U%GsQrbzp|T*~60+abuw!`_kBBjxO!cAiSU z-D%kV!+-qG{)>O_{f0~Zwb$16bJr94w3fQzwEZpS+yY$758Mf|s9COu{o1!f!GSAw*jpMLexP~FU-r6pnLM+C11t&xjfdjn#}*tnt@P%Bd=R#bFg=);p6 z%&70AjK>>xs(MXQ$HX>!KL&&6rEcbEcog|3=Cl`Yp58YB9*b>`Thm^)=y=7oOc-{N z<`ENq%iuiiMD52>b2YGH*I88)ZSChmy57pV@7&#hAWsleMDa7?wl-JV15)#i)z5%L z?#&`}J(f-&c(yIM(EKCP&lQWf&E28lBKb`94hG+lyp~LnNZ`8?dZqPnEBw*gCkPP( zK7ksnIp#iv(bfiQr=_!PS=6oh7J-yB8ZMg!Z$0vBI;w^Dc$8M17i94b- zardvdP&z<6t%}7pg7gaGZtc8X_tN)sBpjI%pX!o}(Y%yh22@wmBsa*0H5e)7zIIHlc zg=K52afI3OwK1ubhxa6&JiE{2&-+@K$KH#^R_`O$ku3G3xVFr0WY#Y7DUM3g1U5kC zu%H)@kjP{vV&`@eBhH!_Bt`|%(+#IgCyz7e&8eYPxkK&C?N##YPU|ks42LPde8`{6TXX7vhUi@+3J7 z-!u%o&^x!OGKGpy6t=6X(&kDs(aeglXX+Ez4$8i|1@Lwg#Q8qo>8!d50IAu#v0##q zgN0ADJKgShJG0StXFH|%Hn?Htx6N``jorH}3?#Ni#|OJ01Ui3giH0$1x2S!>KTALDnJS9rWOH1|B5h;5_-fUt~E= zXrI^#1jLI%kbn=q8z6?y+cRmikP+S#9|w{XaLWK`+DSDL!Yu7R!ppgV2!Wkk_YyWP zn0`QK5+_5hw+Z+cmq5D4>L0sBubP*MC+^)2r)pJ8RkT z7ZcXPpCd5HxB>N9YbX%lbfCa6YrX0q?^fObK}$D`IWD0LU2+YRM`A;$mn^QlI7D-- zv;4DT*V`1#a>{buVZWE?fJc9D;eFLW7m2hx&_ z{sj_Pw=I25Z{LEHuMG?STAW7|mhIjxqW5ZCoR36y)`?Aq$SQ7-%aZYp8pv1$gC z)qcI4iVfG@!VG_QMbYesrN(pQn7el3xDq}DWDS(LZMKoZ*MbnQ@wa8?mK)}ZfWy{# zVWNUt1+Ol(#$j|;WxOa2L0EvfRqo3Qt=jKxoou`2BvVffF06XcAvc$&ZPR2W1q@o8sLQ_N;(HG$;KX;a;bZst0a%q#a)(6I=X4w zS$7C(qwetW^yLhTC|XfMNv$I_bj5JVtb2-8B%w5Nn=RrZ#npc&xhSea8LxEOs~rt5 z4tHJ|+B;Ta`bBdG7H2zxtYI~pGzhVi~lP2Gi3rUZVZ1a&_1 zgVhZLrBUv@E@r)fBxD?pz65X`6cK<=$e#gY$iGZ*IMHkyl1w_Fuw1`)Y6^vR56Dsq z)vHa(vu>)167_`gWBu^sXvWK?s5osr&3y(|UfcDB;UOJPTL9=2!qtj?2NT{TypfP- z<_Ib>Y;_d?L*#81gx%?k0(wm-0d^%5W5TAJgSyD5CkL1na$MW8!6}k>qXZG%jd@Ij zLNSX1{C@2k*oVkp@OaUm8zJatbSIc2(7X&*FCh6NBKVt>CecE6$2R$jwZepqaFX$n z0fRIP!UhE=?{yZpaBjYQ&x9xYqJ`2$ zhNJoK5br?d<2s@Wj-%h24>uiOvm}?>cPVG7WDje5?Am$dq`5o9hFrZX{v{17wqu8| zuUT#E?e4Mdl|cjEB;w^gH;lLWweik*3w(q4n)n@GKagv`QJz8kETiA0{9GR4Ur~$} zR#4&cDBSbN^XYu=U*#v}Yk$LcJqk8+d%XGd5`J88KVSHnvOx8`Llo}~r#*CxGu2em za|II);cdt>sakqgZU)vDe)cO;kXE%}HbrBj8hp;>Gh1ly+u!g|Z%Xf>T*gK3k4Z%*DNg@wZ_b5F+`H(u zKTl=*!@RzOUSsQ*w*LR|AN~!a-}n81OaEQVFU~(&EY?e&^prN&*lWmWT25Pwom;fV!*CdRhtD-3Vi|e3z*F1KZ^8C46g+He0=jAb} zO(AYc4gyS3ui7C1r@U#f6>;IT1;C!UKh}Ili{SDxNNuGZ{{266a z{flGQg0EX`@RlSbop`>d8hbL0y07sT;Z+xZR+dG#w%y(l)JyMKfNSo1BiuGBlwFH< z_*T-`Xw;3$^QtgK?zJKwC|>@3b5&9i##i0R3jy!K#bM{CyBEoU)P7u83A4XVD!Hj@ zV)(iN?;#m_pe;)}xVv zZU_kj=`TJ1c3*6fML*ia*Hm9`I*0l?fbP4TMECo>-(q;yL&u)Y)~BxSQ};Rdsyo0L z{=r=jeH-_kLdz2O3*5g1ID<0)hp};l_0U83GsopS;4T;jxa&b`>hI$#vZ=ZIhT^}qo75Vtdkf*tW@4lhSx7j8`Si*#M z-WFm%N$MHsCy8{^zG8>Z8cW2aD*`j@D4s)l54wmOdzA*w%KDP9}YNY z6cQpFaXDHE_50)bF~&K(yn*s`qHyqJdU$_Ra_#|n%I1B8HaSV)KYhFN%LMS=9niWn z&nyZMTm*zZB|-p7hlKp*!ipvy>Txox2_G_1jMYSm&PqKY3bfY_HS?Wi8;{}Y87e2d z2ZcuHu@rdsWjOT>pU(5sQ|;J>p2&ukc9%!4lSmDMswiop`3nu_BF5HhdeWUItcX|q-i_* zjs1Uq;d%eL-hQ0=|NZj$e8Z0j`lVlSupn>!VivO^_c`ILgYV|kwptgESB6!OB}{0+ z%@M{M1R&&sBA02jK#Al1gX<2VZ!JH{yFfS~tx6mK*ENUuIU&hBn<*;|E zT(ZW!SAPGo{0LQaq`RwWe`)Zo$HiZ}4QTmrgJDQL@b4cu8EC`HckhTKdpl@J|KY5u zd&vz>#GU)!d>(%F+n>|#>W$0$|M5fYYbo1a9<@6R7|wA$TalyY`MG94HwWjY1Gf!d zMll)q88_*=W1?I?CK05(slP+NFSShkjD~%lpur`%4~JLdGYAF3OV*#pYzJMRAuRvP ze$($BGT3NYZOT)lL7y7+Uhe}p%+8e^m&s|u(Id!8$44W!;5xkQTIKR2&_QqysAc;v zpMy>rKD|y0(!Kwr>usT-xslS|+aEjAJ6wMJFht3)9AOeWpSN3#_u9KBqR0c?a~f|x z%=u&5F7Qbua5@lAC1bZ24W4F{$I5y;98_HVyB@P$S#Q>W%Y-5y!c;Mr_h^vGK-Z%H z5`KBzAPvrOU{$h^oU z-Pxj(g2}2OpdXucSLEn03uFRB>=O|Z{EHW>tR9AL%j}0uUETNUK5CfBmW>a<#NAwq z?-Mq<*N*vmiTjzmQ3j-YKGxdYFRU6A|9){_HhXL&ug%aX`>!1`k?H9{2!cS&4quVf zpBI4-dH%(sFz1h;tkrW|d4pfxhRYC?0iO>|3(Az3e^B zWIqx6#c*d!PC#Q%$gL2A zee~{0`=||DpQM4iqMZkqz!<}hROlB+cp7@dB40!f^0R32DmBnSOp{Vvc4dT%yqvKa zemo2TMjyc4zE)=~51V0a_8EIaG*ahzs6Eu8z<`X7_&uD&J78fT1f8k2)SFsIjRF+x zMR&@Uy(Z;iOjyyx9;zQTzHK$mNpVb+D0o_Ri))P6T2J<|%HUO8t)uP=y0)Xv68?&+ zWewd??@~`mJ5!glC{*0!tZ$chKHiDvAmmHANsilN8!B9#wp3)B;UxqTNtGE5_tBj# z)hsB(Zo`moYv(yZwWnKbdMF71k%voN-~vg!F$CO~pagV#{C-WO@xJ2`3Cz*&UIdQZ z9ls0CehrR@tR{CLouBPEQ_yVE%Bw(<@X0vQY)u8dtP*Xx84{11491^ON-L9=plcH> z+1uz;vb9D(f@qx7X72P1x%ylo;j$^=6?KK8zQ~?6d-ZOE#bWJN5Gs z1lT>cF5n3%&McxVczm*8Ddu-UB0cSC@fy4~)DKdc={ld@Ez&HLh{2pFYK( z#{XQhx^ssE`soZ=J_l8^l{MurRrJiCT{-}Zt8(jYH$SE<_d+E@i4X-w&yMMEt;nsA zf}<^1gVykfKc4Fs~e(p0%}F$`(Ig&~-)_5#b){WE2%;^i~z6#_g9;+M*n%uIr{XZY|v` z$s6Gj*peP40LA?EA^vd&+V3FS(PI#fWJ^v!WADhVC`ua{Tu#(-rL-p;$E$lpTi$u@ zCWQQel^lo1uHPRiUZ{Q17@PH;XJ?qaNB@2iM@z6eLGOke zJ4#~(VT)c((Z?u4w4oP8zlUFgMTs_f7Uhf6DcJUEw@va6q=^>W=jk!%!yJR!9hHbZh2A4;NCqRm*{17IbYp&*+=?wSJLPU)!ac3EHa-6Ia@~oL%*w#D z;39K?8tj7(nx?wb)my-$ccQ`@n@HMwJh{bSgl%4G?p(wW)Z)Um;^L`UclhK=a!K7Q zK^L!#?rf{>hBc1~x5Qi^Hl%V487gp7SVJ*KaIi*d$tn0nipQX$WhfM*|C>dos1_q{ z_jdzU7y`M-ZsGIn^N_YD#bfY3l&89V9h90hKktoV&NF);c}$2JYL};Y)6nyM zrkGTS+?@NoDnJycv@P_GMoA>+10UA1S>kO|D6SCjfd+|B^r1xts|}PuKJt` zc+{P!fHa7-KO0IO$hwwC=zViQl55gF6Cc}_JrE1N_&)nC;W*paWqTr4>!L5INaucvWMMNzZg zEZ-gC8`Yi+N;~1;r;s>he(Eot&X?1@pMDYjCBLxycI01r-o6CG`+bp9|ES-)^C7l6 zepGO|-2K9Gy1s|;nhv6rWCslgxWh8l@$-+BjMp27Bi2c=C1(nV<4adh0WZ;=s3wy3 zUSAxrS_7N7y)sH>rY{i7dgDxeSDBwYgyRpH?eU0^o_F@T4!+$jz2|}%0FN|RwPX3q z8r^=CA!)zaku5n=)FJS_S_*|zz^_bz<1ghG-w@$;#qg0AR(|&L{w>C@{ztt1IrV4r z@AKFGUCZC`c2Fs0f3eA=l-BTHyLULJAxln4KG@LS9Om?CP0!gP9WBlZKjH&l0&S zN$B>rXM1JpgBQ_dDN2?o`?BE>TJxQn_~2g&>uH!62-V&XUX6G#Vxz10|aZ{@38 z1s7c+)J5Git|rF8c~!vLTd$e}Yu2G#aBffN;(WwJvD!&9g=Q4_ zy1Tiq59yP#4TatF=#I19>MmO~mV51cbB}S~%pFp>f8buesaDAy$$NCxY%3#OU0k0B z$frZp#e0qKZOuJ&A#fw2mImMt@9h8hb@`e$*T-FJ?u(dy4B!GIMn{&=yH8|Wx}20G z_}t#6^CJ}7g|$50p?8V7={?e4nwV+9(B4!u5vkuSgC_Srkc zwjOr^)pYX&3C_o{=PsMhCPa!kYufCoJ~bh|i`@?HeroNL(ED&c(pa!FDcyBMb2F8? zq2)uC#8z(+=8=*)8e7h-bwvd|!K&*Ovw% z;&OciZ3@5#$7=txD$7-{vO>rem$ime9|seE9OB(cb6=s}&dNMp%CU0PPD@`2?)%td zMCA5umm#)UC}loNfM#jnh;={5t@dV^$};+f4QJg&%5T$HGwV4RfARm?drsrc5lMt! zHNK$y(63YY6k=_Z=4^4w?-0;i3PLOo5#T}usu37oEY0%T9pG3n%PIFHO#wbHHr^lk zAVJ{7ecD5+YXU_wK4J`+QQB53pWt$*!%3LKo9=F&Ba)UN@1~q((v6ApN(gRm*VWvu z%Dr<)x=ggEw6V}TsE}pROpug!|1DWL)X$zapI|!j#S?DZ?mG6JoEGGv>NzQXONE=@ zsl7|@Jo>ArsRd1Ut>>RL-s$~B z+r8hcU7~C!Uoz6Zmc(cKxH7EpO{a9NtNqiy^%vWY{Cywt89(rCukO#QXI5YNJHE)< z{>6}35mATN#lXcGjS)1m0 zhMaO*YmtDDK{aA6yDb8&eFEYOzEuX*b65Z+?)r1iJG0j%)r3#B2y<@tM*;iW`WS_s z9*Z1)vexnyR|N-od*Z&RLbS7_uiHEFT>>1LV!}2XOU(F=Ix4h z2jrW5-uFNP{=R44{&rvI-~0PMC;e<*{(L{*Z(}7ae{TF=bENouj}JHEy3?S@)p}ZgAw@gJb9seYCPbQX@Yn#Z!f=wO2=25-&WTz8zyoW1TMRe!d;gi>ayZ zrIv?r?gip9^WI57|%0{Y?d8j*1O>>Xm8LH&iuy4f8&Z|Cg!i%qwQ zkg~JZmh*Fj_sLas_san)$;NuS`Rf09$@pA%J$&4ifRrz(_XN1Y)@^53-AB$Hh^S|J zm=?i*D3(}=Yy~;0AIL0(JGpy1$@LBBA8j{CJ}zb0zKce-1&uIvWHW)vT%J~UKzu3w zvQ0`u;w4L+g47XWc|+ZO*^~DjnMvk2YJNYS4L8}cH^G55#mi9llSY!08QDeF)Bt)x zaap`aA{*rNYSLr$RGZD3CR?BFeIVb**J#3GQVNuJa9qtfnY#}@bg z=q?-YdUe;%NPdC)0;n?~J3TUNxm8y1upng3#iuJMQvgmpbs!VG5WAAPvyEHTdx8;9 zylPF4ZS+D%aqz~-B)V3|punk@Q5Hjv6M~|hvKwdE2e-z+5AWI<0$i0gsRv&Rbr^N; zKnx2B4GQ;1UE7&Pw9^}a26PjPJA%pmAo9*R*4Iv&yb+ke5;kr@?G&_gQ4WqKR)RT3 z5;!O04+u4#fudpsFKhag^-#s>gMp4}Q%r-8usjs%G7hE8KB*x@p-H+foWD za=fHxZ5z&>dYj5Rz#gFcM!#S4_#H%n8c+PU6FNy4H`;aWj;E0Iqw4^G-yvoNh(`T6 zc_2+n@Ek@neEm+Eb_x6Y7Ew-sWPCBZ-O*5uvPFbfbKPn~+b^06Y1q|tdPfgIG_*2m z#*fG%BHVuC!X~|?vhR5*tbIta4 zMejR$KRVpY-zalf?lAQp8xL!GYlReQetkk)^T!>(_fM;zfH!`YSKjnLf6K4%A^5xm z|C_(mAJtFsf2>YDK%7o5oqELRy=ROE6I@PByvs=hms3&n-W%sTUBGs^oGt_hfO;_c zrJwo*kia@!$QRlEB?2KY^8MlS7{-~ZB=-KVKcM}aVE$?Fh^ID$eM(Uy>eu|#U*lhT z^&7tV^cQ^EU(A16@8PDsp734ae%lxB0tsuE`0*sA$rs)heqr`54|sbdo90?Fyxcnd zHSt51+sfB!D60u;YWk~D>jCnnT|4_gLUMX!*z$z<3y+0#s=I57SXWYfsBS#<+3>D| z+S7ZjdDq3ph>vLR`8xMSc_Xc_{;r3)`8mkaCm&zrIO9vStBS27;8Win50{s_(mKu8 zjCcIazI)Ptzx;E^^X`3k<_gDNgQY7@L7Wad30C6H@r?KF_KBO>QwZ0~H!6*DjeN^} z=_VY}fUJKzjIZW)XZ!&Fzq``)uJHeTMU>fZCRd2&icP2x)^f!S8}hIDy?%o~w`{fP zUlPU6jjg47E9ER_Ewy2I5&gWI99RU++FAh}!3wZwOJ&8YKjkDILw+hG1ldTt>#n~@N_;)=rw!F2{h)~ePs;lkS8MlGssfR3h z6Z=W;&bX`Iuh;iYcaNRx0Av9gMgBas&j8#G zJMp_}5yNn4Fv18mMk&W<=Sx0D&YW}R4>Obh#x0S>^(u{}ef8+gFl%}#GqzqYPq~|L zgiE7kVk{0oTP+^6zv2YJ6=`Gn?NGpP1P1{}%ro>3$isp3H(*Sd$J9Rlvlo@{-OcoM zH%sf)y?6HvJR9As?)%E7bMA=w&S=EFh;s#rz8?CKJYt1a)1)^&b!+a{-hh{`iDZnt zCgK&B4G;p+cIrw#uL2Ye!sPdTTq+2FwlDbd(?oW-DD0Iv4;Q8_^*&k`OP#wDbQs8% zy$3GkeYM_|ImDVJfc^T&y<;AmG=-J9gRRFwqu0>hEVB4;_b&a{R&9W4)Ln{@hy!b` zMqQA>pnLo;5Jttp?Sa#{Y^rjDOX`l%N)i*nZp%Q~tValp7Hbqu;v!*X`0pe)$GQuG zxs862{n_E)8?@i~7no6b&-^+KhX@U}ufYShRqO}P`mwR98d}U2X0X(t5 z_q!!P+!8`gv>x=$Cprxr5ZJXKNFqK?Gv$G$Wl*RGC&R2EXT z>%8Oo04NZ>QJ&vaq%!G>Xzt!$9B5}V2joJ=u_Gz5&KFUs6PJQN;D*zMKvEhJ;>c{& z*4`Jb0lP-sx5dm;PD^fs1%g}5Hm`bstXey{HjtneuK*o_`1=vzgr|fY8S{Njn01F> z_wpeEmJ#b9=P9)H4utQ>)C*wl*JXe`kQQc0K6s29TCYNg$^O zxiu7#uQ#K#?RSkm@p<`ZN>CDyQ$L<#`lZ$VU|9|4Ufz5ppC1+UAU5Q@6!>mno4-}_ zyO_TXkxD6Ye{u}}5A-vC}1>DV)Wy%qz%sqMtS z1$a_&7AP6a1NnXIYfP-WAJ;V2`p$aZNjmnc-c7~cky(@9;l~|++8h7upOA0;4}9&- z=U$?&dw}^%wk}w!O!y2xn}9E;0NTKB%5m7U$dH`b=>Zb3VX~F#BHVul+Q0s}6nG|C z<@o2ng#CBJz6uzrqm;jzzSE`A+a>tVm%hrc#;?e~`R{)1-&p5sft>rb^K*U@t9G9> zsIAS^=CUJm4b5TmO;qZ>ZeS5NUhW&*T#1B3(>@XC(Smzl|AI-1`}FOzF^h)9Wwvou zICc4OqbwS`qCbV0-4cvFe9mB#smPO}y)&_1oS~4DQb>&@&j;qsFt?uTl4gD>)Pa-S z6y{t_g>jLPYjSh)Th1K43*nZhuvG8Mn+_DS2~uB8 z-Uqgr^82RmoawM8OTDfrw4b=$9cb-?n@^y8lGQirui|!hy}pXu-Ia(r^Z$>lKt9HL z1;wt=7z3J*i`}YztKb!WH~Edv{t5q@uUGy({nfbz#J-+&E$eoc#^XNO)>gJwwz^Ms z^T)e}=nl!vQLNb`-le$RdJWr7S8nY+!KsIVb!LMvzm>?=qOc|7DY);z#X8;#dP!ml;ccgm{ybv6R_|8RH+gbniU-hFC-i=k zQ>yvWYG*~HgMVF}FAm<$!t)DYsyR~U?gSkM*5QB7XoD69Kk!tUUaK+J@=RA=h!{9UihcDl7czfQ zXnn8zO!SRm&++}xOIul)R@BgHiyBZ@`pcSWtHBqwm`ZEFYmgeja}B!5pdWq<_9kxTe%XqgVU}%zLS5aP#kec)pSYj2@EF{At+eza z+HO#>SkA<~M1BX(qgTLv6L&h_s+I&b-F=nn$g&e(=6A9I0zx29HLbmB+Nh$7%ivD) z*vZ0^$QImNZ%DlX-I060^0Xw7`j%UUjushUHAKPtBczST4_Ry z#h)s_mpo_ovYFk-FQ!K|;COi9gOE&B8OfKGFt1L6dsBB(%oB=S+3Ak;e#a10<+*p| zAHRoc> zB!8y;$(W$62@_ZaGXYbeMNXq?BE#iL$fWX{VDLaXZ|62| z@^L$9@Q4S!yUlZ*u%DQOw%Wwcv`sJC1q|CPNlG~J$$q~-Yu#C{lYl^Xk-H0l?2A;F zl+S^62HqF~oplE7;!rVN>wvdnY9?)Y40RCHtJ&b>Ku^t860X2&o%~Wwlylp@$Df>-Szh;m&cPB$ypXN3cS)Sar_uKV_`NOh`v zK^8R)cTHSGfag{b4=&;Zct;-y$bL;&j;tJrI7Xj8h3Mbc(ve4enEnxmzrpX|2si+z z-ytrC;q2b1a=4W7gjItk?KTNfs0t&f830YhojhRSgvG*)fyoE0-mUzZrt#&FZbEg) z8am6YK+_7RufydDCU2 z8O(Zn{v|NS5TrRe8d`Xwh!%%ZP^FTU|h z{yhH0_+|MMe*^V?!}eoUo_;!||1D^IMAvaSUt;(mBi-5v?jY7-!#S5N96NT1Yruxv z4xMdHPN|I3yFy;;bt-sU^YcEHl%7A}K_6eeR2dbW>GPX9GS2-i5R@dw<2rvxBYU-nb{bbAKbE$?I$E8zI7Q-tTSxdSk{rAa=Y9 zu*N$wzm#kWA;TGT!r)fz^fCEr#(u5_gL?q4_KGQ^=(GFKRGN}!CdWZM=B^F!W|~ zT!7Y}X+RAT)(+9&_3sbFUHSi=aIcOROm_R=gw&_0&yXJrxmQETl##6AivxZtj9+?r zK^~L4M)G*qK_o}1#IW^|6u{rRvL81mpnDdV7W}@s)<4j#oI7}ydZhE&hw+W}bPWwH{ z7nxbx%yJLEn6M!n9HYVGok*stjO4c?VZJ&D?o-`GF=Me&;P_@6USKiF)!AV-zrvi@ z%bNQnuei$aggS2(cJcMp&})#>KCXO_!gL|IPy@3_`1F2!JEIL9k*es)wXDkBU(=09 zdbs{}9JI+Idq;B@BCf^@JJ;E0Rp!|CMA{@(k@vQc!2DX3MU|<3V#;~Lwx)PqHAN4% z5zhhK^};Rulb^Bn^)~Z%8|-&capu`luSy_fOwr{pG{#F(C>B4!Aq`K5KqtYpN~08_ z`e8kx?Z4sM7UQh2Ti8vX#z?YHbSTFmVZWF(D4$x;e-kR|o}0T#mQLK6>BYV3E_95# zNLprsPjBGv!Db)^mu{F?-cEGX$9|w{#>Zdr`p?BsDDmlFx9QgV?2A$LV8^FH%}7)m zb`^52vWHECq>;$cv7_C(!Upc)4{+BG6f=3%))$Pnqto7Z=rI^};|#Bb&gY8W!?OXa zUjBqDk1AyIu?4frPZt}Zg#QE+X+*Xi6nw}9l0vkv4+rL%!8p>-$*9ldsM&i6;?Ze` zEJ*rDqa7cUg}T()IB-k}&g(#a9cZL3RPt7Wg%*(=Wt0!(gC9mD5#5nYtWX50R9PCK z?Yg7PsEcGoE-6S39HU8_S*&44xJpWmo{XVJXx?F)q4w?jt)3$8AbY~_Bid@MP2=?L z^x;UwzHAzs-2{fqFJK;VN*KR;x~Q4}`VXibLYm%`pN#kG&XeAS)RK^Ks+YR8Z=vac zj{#0VkMuPp<_2y%@)eIGkoi!d*E+&IC=}v77^rdvL`4w@n1t?eg<-2Yl>pspjP202 zOkpy#@Nx0wW|g1r7=#l32`123wbO0ObDIey673e2vHVSnB z_F4qFz_M~OB(^~j&d>a_j&-t2l}%3Z>vhy!1b-tVzlO*husV7bqq$|K5)dl{OJzvv z#RmFw0?_Y*zN6n!D%#|6$RpP*rx5DSn0u4fyh%=0NyG)AA~1iGQ8yz*D5lA?*=)m@ zO}K7Y+V&H(H}~hvu?jYpmY|c6-sH)PSfriVSUs@ArzgFSN6D#_K^5%FxBF{VQ={i& zUQ7O7?+w(7rHmCzb9k^* znYxN}??o*p0C$m;XAhqHe(7($UGEg-jp5q!=RHedcW8ZZ$0fMlICtuF3%`FcI;_8l z(c?e)#3g7r^!R^{>-HZWC?;?lxLgF&`~UaP3HQ${qN0U!w`%n7^l23MR}H*U?Ny=l z?PnbLjQDZhSx#K;IxIYrw|2Y6sEOyLxGBOZ%EM7hct;SAPCMjyWzCKge|hkeSYzca z4|a0IG$l9($7QyGMryd~gZ#%re~SUvoy$9?Wu+2fPsKZ=?cIs&UwV&$kDFIvQ$!3n zXR}K?Iw{&rw^0#{Im-b&d=8uQzXZpOJ2NA3(nE1TSL$duP1( z@14{nZ&T2FJDk`q<@oXR`EiK+?2}9RGtYg?a^u-6=} zgpJvf>w3itQ#E&7KiaZ+TRvLfq|(8YlDQ*b9ru6 z3%jinL;%$ErW&g(F_Ty3`36+w$Bd9g-03CO|&SGlOwUKgXztH;&rg8$^2@PGMu%JraAeTc{*o z&pL5dZLAx=p5BR(-Us*S$g$~h=ddEI-{qtdU;z%<)_ab-{sAn#Q!~9JBe_}#I7>-e zFC9BFtUL-O=Z+d#a)fw;_PY@6UWi#GU34#kKaWX z)lkn|nYlW9#_)%a!0;@UM~F?{+GUeO_lUF5S1>9=$a;w3Ft$i(84ROk1|laf9ZbUa z)OiBlYVwJEFf`zR_F!6ibt4kta~apP4l3?!?-g26_t7HGea@ZlB^~VV?pmCwdADo2 zGxSaxa|d46=%lw_Hs&cpaSC*#1QdO1ngmqDrZj_fy-P;DgZ!(6_J!U%jFL~DvQE7RS1;g+v*zN) zdgbhLbn6W1my=`?pM>|wf#(@;_P)(g=+Fp8$sLhIvllADWuCGgMju*qyZPg;AW%GW zkQyO?5-yHe)utx6OB8rz_c_(x7`b;@_t~^YiRIQsbrUd`B)oo=LU5z*c?6Qs!*UA( z>!@wgIg6SzLM1vqR9K-!m?JY_Oy#Y0Hxx9Kca&@ZQX8H}24;*` zkK3Y~NE zP`b_S7VbZw0tFG`qQb;)2-M*8gnWjjz8D2)YpC^Pwm>H8&J z;sr5B6UrUkx}w-hR;!Ytq>t(5gBK5e{tDDQqtIz&3Zmpv@*pbosYUYGD%}`#JAgRdKV$+tLeg7R59X^^w8kJZ}S|fyHrnm+6~oD>#k#zNEQyZK6TCKcjy5w4;z{U zdA&1JU~pgjHn>iPi37P8eEbnqgeKe}aQZdyJDSdbIo*(VQxh6+&U^F2(t+~h+h1Yc>BUD#SKj{etIT?@|B>-1KD~3-1PhkqJP!l@Y4$!e zA3jdyx@(-e{MxBwIe^QFgO#^_K3z0|i2=;(9W&Dx{gQU4H@{#glk?a#by#AW3??EqCfdZuF(_Q|DdS@C?=>EA}&iBN1 zzMN24Aykd$^SLsfyBr{{fQr3y034&xnzp9-PF5X{LAik}eJd4SA8)Za<(mC!ig4zd z!`uMUFg7eUe0AI$v(}I|hOc3l^}VqX+5$MOJfLt<#yYE8M|HQsi2Lj9d8#uq1_~1n zy_VZiZYtRx-!Y}0Op8aSPs4?#+E!+T@qBpe{du-LhFx(0WE(Cp{Ggt{_?&uwvht{i zr2xPx=+W^`G-kZBUS{D8i#{pqGHliyTrRwrf`M@Xr(>^MhAne{SgCl3rjXu@l<2*; z{K4Cja-;?i`Ss;GosyQcQpEjDpB&zPg1m53e_iLe)9o%u=+~RK2m19lZZ5&Ydl(>r znm3ya{Qly~x4V}qUYBoo(1Jrdv0L)7qSq!tvE@wLZ_5LJJo?mdN1Df$<(IAhsyfbp z^!@4UTDm2z{*ERr-!`^A61#sqnZ3|ImYECOZNSdix9|d!?6)s+)O0VoL{k0x&Iv_? zAz3Nu_Lvt<8Js=7DtFc<39RP-Rr*#h@-vOSTgeXBbJbYN| z2um${kL6^C6HUU%xh8Oji1j9&O;sQLIFvq{Qa(P6LZS2isHMG#+unPWe+X?G=5*Io z_uEs}0#g;^>KAH0XU)a^VmKO>JKZ`%`spN@guU}cGzl*re*Qwua}+un!6>;Sg6ILc zQ4!wuDC?P8S4-zel!O@s#j`_dLu6rXc(X2TV%jGPUb%e|26w&p9_v0L8mYax^{DPF z%ade++<8dazP2ARuC~s4ItcdYsUnkW{i+}D6P-Q{7dpTk&xk4V-dwDMMJ|NBDF24F zBk*(}Nrt!#XBW7av!iesV{#r&Mx^27hx}I!LnJtjN66;QU#@>1^#`bSOOT(p52S2-o13!QW8}&ZBO_RCvrazRkNLFF1h#P zf(L`O26wo21rg2V%z7TLo|=;C8xq=mW89oEX|{V*-j^r(>s+k#n%uXzSCxd}eH?1S zRq8Nv+uxrK`_HdT$s}Xju`l{hJ-U}t>RlS^A`Fn0>xbkO@Q{!lAd!vlApd^yUK2T zC;3nC&Xlkyn@uep>6U-Phvbw^iB8`$8%_h#+r}E8@qm0SXuT zF+sPGj2QeW$-adXB)#{v_zxJnlwPRBi*o8tw3{B9uWd3RKr%kyFY8>=d7VQ6R+EAg zXE#L1aBD;rk*+(3e#jqDmo}KWWNTA3fVV9bosjR0;lFDPoR}KArt-EGUtAn5FKv#a z7V*5c()9$mkV34Z5I>KAmx-6E7WH2qneqxE#QnEZ+7#OE{VJcQt3l`~@m>qwfLWD0 z3yw?z_r;PErqkcK3)c~E6HXWYwXAFJx!&LSx=)oIUyIkh#}3A&pZw#F%dK~=AiyWt z{N7LW$ze$Qaz9~mx{NtjCFv(o+`-5B?R&olWry>26P`H+iy?1f_D%;5<)@)+`f(1N zr{Mh_+&67E>^-O&3yj=AdM?Tf%^ABLb}T5F_y6O+7Q+BvK%l?5a_6Dzjnum$d?Cvb zwt8pgn2hzth<_!arpFW9=~BIN0{mWM_~%nU_e;o0;h#U};FrC*0M@=Fv$==~#CrDA z`>I`KKfHUUKE0Ar64(T!a2JPMJ7DjR;4YKFS3|&yg49&oq3pGAN(dSLj!+NgGC!UN zvkd?DW~SW>Q{0cFM3#J+7y#-FOQ_Wt~xU4Gk_ z_hhJfai?Le2i%q{E7Gn__}tvu)Ko7ZLWNkBkX|83tyn&ng5!$?yVj`x)8AJFj(pZu zS}PqE93os|8zYENgtOl|Y0{oII&dj=jaUNfJ;|qGy*ZcqJ&f&ENE=|rp75h60I+%b zHA)HEylk@Fx7;r5y{IU+^H38|US{58oVTV$)(H4=EqA!<#gdfN<#f_4C$K$T-S;0G zLz)owemw@x-mm&lcm{EVFOT>-w7pZ@l=Rf%Mi(Vcl^xT)_D)-o-C>Hr4#X89cLFQ} z?&)32KIB0ode_(S@Mlx@uYE{}ZI4h7=C&U{sPOQkwCTq9`0vMHmavz#DCfv=_#WPr zCqtR?>aj!yEoVP$j&c;Foc{Q(J}U$#oP8?EgNj?=zm&X5;z8GqNRcbC!}kUTFWfzR z7j?BW=S+DrdZ6oqm=ErZv}_svbIcE0k2s9J zaq9fHNpbgmT#ujXyW9ZMN6C%ehv}6m^-d!^Q7KKm27-kRQ& zbav9-LkEgtMg^DgZUif(yc+o&_2f?~$pG49?EltEDk~BgfKfcNaI*lsJycdl-v*W? zrOm@`V2W}LtX4kA>}bD0YSvbix(x2EAm>OHGE@;FyxY8~e@x@M>1Q6$rs{~_9pT=D z)6>yyZ7BN=KyZJ}LBQ`Ma=h__!~+cuwDEZk>1}c22V^4GmJdr^NXQ2c@Z^6OlvK~! zPMd*B)-`lp6YOL*w5}la0Z~V>xK@<1DaAlSrEaDjGC&I$s7-YfM0aRN3p)@=56^Z; zeaq;FAh;R;F_73J|%b_3J9Jd-%fzT z95YX9F4|4XqAMz`X?yQwmM`#AHC7G(d@l1>b{W3AmqEU~c#&Mw)aZ+JRnS?d?o~@p z{ldcuqR>~1Q@m<*v35vltwf-~aTqQjfri<8@5NVZ3D@%Alz^UDb*``~c=!0Y+&hZ- zuUK{RZ~FXygX}Jw{-yfYf9Nu1TCQ29UT<{f{Lg=a?w|h}kbnM5V5MBl_V%sc`c*f%##edr;&Y%qIiwvVIL!IXziduTHPX=ay&9E%!19_XIkg=&-GP<> zvC4=g_BWTOTo3fB3q}wkz?O zsxO+8IfjSM-W3e*=`Dt?fA2QEuZI22=6QHx(^oftOcqzYSb5z0r(9pE%!i83-n940 zOGNRa!nYMWtV;P9d5S@@liEU-4LN)d%|=M`Tg$Nfgxdmqe>B_a+av2?seZJ*R{$=g zCp_|4rg86IsM>6U)HB?>LjJ34Je-#z`Q^L%C(31?+hvBP>xJ*WW(uAU`x*o9cRc5f zbcwLW(-n~(-%jRN)(NXXv7*%~RomtKh$?P!G4d!qAp^~TUb|K*pmfV5trFT_-8|-svMM0iiI8n*J z54gxZ*=x44?^sw*(|}KWtM4zS*If>)LkTZWfPi$t%F~D|V!+amo#ZoN#&zC3Vp-(T zno@jcD|%m;a@uJ@$|);3Q-t0}_$Q>MIA*4LwU4`Gvd4sij$sGG!DlxWdDPl!v9L$w zfB$dw#CuFXTE(V$LXSYv9e0ba7ct8Jg}mA!AGsG9oUDY%-KAT|`I|SN6vjvP<^Q&1 z5H|E7u$4#}hPwP?tsvwdi`D|VQPf5tv~WmEQjv-Y z{+F0c;Y4IJ&UdZCE_{=pZ>km$63P?LwLc0Om!JNytS?y zKV}Qpk3{%wN%^7)!9ZTinIQ+h-SPOyp)UBUUg>Z0SDU!F7Z6*kN5Y?tkB7y1SSDvQ zDZ0MBZRmXI%!Zd&Ur#A6=AO=edsq0RryFG5@rYpN-iN9NdAJAqBjA5ZMxQ@*%@f%! zX}br)iv-+H2`SgaQ$HIrjz1zTM`cZ-j_an!CzjMJ&54I5f( zud)1yyvA))Kst?6Kg3toXE(EydMgNotCvLZ^KR5Qc~(VX*jyCbHIYfg#GlaYwQjcn zk)23T@G5bzv|&&*5@z8ia}tybr{D&t$#h_?P48#l3q0H}5Trk`CXt8l1XyU(M1&-+_jO9@1WBhnl^i;{)w?oqVmk`q<#HX93uMhkXV?#6 zV>aD&lo{tRHNEyc02JYS?{(0B==q_VR(d4c{!(TyligA3q&Ue*HhZtFcItb&3Y8Bs zxkvzRUcR~mr2G^)3^-OMDa)rIA$r$2A)$ds7WTd@lfQ7cy8THes}kOHXTHb5dMg7+ z(%==0Y&k2lxeN@K*X6zrWfO|58Or02JTAJtt$OmpRyNHTk8@K0Dd)C*hON0Q11g`A z${4^ozW- zV_8Ze(t0Z{ML=I@ZOSB4k&h&`97H$;RIQAy#Mx5qJ^hOWp{M7ejX{%5J?_Vm?9j{I z5*%I{8%E_MLz)288oR5f8;D!HCzXtvL!z9+O8_k|%}N*LXZy_CQIJO$4o3QS_BMpA z_g9H*iT6un-Qq0FAgJ2A2N(m3$`5e3j(XhgcSQYpICh zud;c{8m62=T#$0gO3oC~`&s@8sTs$-r@HA~`j~8VGzxkRdkB|pdW&4-yba)&p5=&wKwtr1v(Tz6LM|ZAK}Zfy$3cyS947bb4=c$<7;`uA|~<$vErR2D5kH z)#d!HWWQ`j@^#Yp8%iE7KSBE2x~%T6GrTtlFBMIg;%$@AA;i6vnnc|$(JRT}!9{BA zs#?2$zY6s%36?NSn%xx)2a82oD!PU*2}Vn6fOJj54KZ*wBu}K-+Sz!TUJ-j4;`KSx zLr_Kv^agdiANX0X{O{V@V`%{fe8oU#XWU~BJ=2|E5O;EU_hRpDSKLqBd$h;xRZ!L*8U?u?Cj~o$Mq`!bg?Gp1T8QLh|4{1ba5}77 zJ-V1RTJFMd+-PcwY(6R&s2HKgXW|}o*?1Jkg-;-lf_v8lMHHVm8f$=bI0g$JwXdRx zfmzq4MAI&-H&myf=9}D5%y`kb#B+G|IH2x~q zlKRox9fgzlb_dbI8eDt$GF;=*ROG78yN2ZJ__X!p^9$Og#*NI}O--KEny zySTh+TkF0p?+h4o=^ft{rLK+Hk6UYQ{ zaU&JK1NsB0V4LS^?s&vAFc3-drdZ%Txl)^ukaWj0A+B2sy>RVG0fn#oNDdJfw_xmk zNW=||GvoUaZjQbxxe9h|DwY`V#{uHjnvqqMk_L9?bXK zkqt&^AI-lU`w-GRN1H^Y@L21L?^x>YOGd9L>F;pl;keF<3~?b9Mx%=!NQ-fCv`Pz4 zrOngi$6?jG*U{F(CqwZ>X8BHI z&MpESOJoC-k@lE<#=u1-5|^(+9;2S9AJmv?tETbVa4q))s-mx~A4F6*dza*n=O$27 z`bz^|*Dblg-s=Uz<<0e6mFoRn8Dx-VGMH2FIHUJaxEw&2Y|=?(Mq|7SMsTlLCVCozYWh z54InE>|-1MjF;>ginRRL3obW1e|q<2scWS?&AGjAX*kzs-g!KU3y*J8)?Iz{5eeQ$ zSGNiZ>yf+`V6e`V%8l3P`+wY-}J7FH*mDpz$rt@h}k*U9c=KVINLE6iSu1E}kwhHj(tRJj{LC9#W@~?KL~b+-%TI1cuq5 z**hwFnRkmikqiQeHy}nmQK24$$3L!qbXGkb%e^>mih~1iJauwk(DqT#i_*mbj=00c z0ITUfD3hCKZZ|PW+LvXS>>IR{hb!r&0VV@nHW)xLe21RU(G)fD%LsYp^u>EYfxCw&u(F;`{koq|#ISL%864cy(U z4g+tk1aU0=sz62WA;Xui%HAjKyK+IXhcW9ECih-UoOcLqZjg+M$}b=}gqpL@-U+=o zTaW->dU|dFLjN6Nkm0d z!|*}7&!gTQ68f&S9e89*@4G0vKAPw{wS7cw?!h}pSm^Fpf72Jln6sUmy`S+gpt@M6 zz77cKD#`SZxJ?weh$P5Zbrsq$(mpAIAnqRS#tbIOZ#Nm$_>-;$(#7$}V=?a9{pQ`V zcCdoeMYbam#2@H^hMED9y{pEbfDNcrgS$C`vx_O&x|lo#)<|uzJMgI+U#37p?oINUFcg0<`%5wyuBgrb_WmNqs13Y)I_Vjtc|OgjKYAc)LT+MV7td z0-W$(^p&)=>+Mdp5f@dC42&H|k{uDmofjOz9Lil+lg0r=&KX0H@SVW-ku+c%t>PGO zWV;f?ZMkj1u@SjDp$>ct77r)F>a$Dej&gClK^Qqil0)3MGz1|z*nl#H;73paAa`Lp zXl6{kNqf_56j}$ORFIJ0ZpN-TBiygMX`h+gmXRin`bdUEU<>~yxg8qH4Wv$dt%Tdo zIgac8meg#JK$rvSSbT$L>3Caj32y6fXy^5il-Bba05>KWEv^~TPeX}9D}*pT`(1*b zd2Nj0myb^=^43vo(=10axolc5;?>l-YS)ktfeI$4C zT=jZt$*t(EfjAt)h}-;!-b0IuK*H*s3#l-`0Q3}XiL%AYqZoGHVL19I zP}M=p-J{&J*)FAzbRC3PG+RmcR|g}B3NZQf1r)eUH>AF{yZ7Z~@y*zG;FpzG)YVp7 z>5UV=jW^TW72wl>-nx>UToWU}1K!?gDU9Ta@ce>&IE$x;)G{P|YrSs_@TbV_=PAlP zO3fZUF|B!Tq_}0`8i{11%Luila>s)B)}s(Tvzx(jSR`zq_p)crd=4fm&g4@T4 zzTDUQzGm6?b(VeE@1PE_=k`7-HRD2G`^Xr`WJ+4eP=$O2%#wP~_FP!ptaEW8a-u4C z_d9pE)#MgP+17_Pr-oia+cL|ElwKVQ*ap6AFV7FTQ@a;a;!{B|7=7%8gHMrd-21X5 zwaK>#Ykl{)eXo^}$=!2bPp9uq51x63@?o7=Pub(Zo%U15$NwqXQbfX-W$$$(%PPbA ziIV3Lq##lpr#TU~`F8Gf(^=|D7P(InHeuNiL{;}@=Y^OPbb zvKfzJb}$qseEM}j_rBa3uDm1KRa8HLB>lLKM?21WQU;zaSOCM*Q*!H%h(QKh@-v_p zj6$tncl&MZr9~rDJ#%RGD0c%SUZ_ls+@}>3a7_2>9-GU*ti+Gk#WxcIcpbX}n=saN zlK4R?2fa;k+tPL~-iaNi)xo_NueCY_%U{?a(|zN%18W5RynRx?P2h8ntu#&`Eq-Mjbdj{c;u?qjr}&6ZtvS@|OOf>cS01IkFWrEirM zUf*xito4$+7UqJjp6-P6FZCGnIDXEBo@N~PcG{w#$xVd7jcmy2AH zV2(SJ9)D>BbBwZ4{iApFLWv(1vqrlEW;|UPKowCr9eg?<6{O&eMu6#Cys9?6e>eV* z^S9JbWQ#%^z#j+;z@cSIM`fiNxmBw)OO(@8bhaKlnNgkXX;B;ghvQ6}4xSMwv$geM_U zH;5G7o~$8|efBh9$h%^$&scHI|I4q}jjKP9<42A4yy_fwLtV_$&tk%^0@oD^nY zXgA6f$-==gPRbo3YYKttR8o^2oiu5_6C~$G)6|Xl;B%ADN6*6j4gclmCw1w;e}kk5?TKcR;Xr`e?K}=$dt7(2uisbhbeVj%Cp0+ZbSbPHo8ms$_gv&b z68Y-Jue*Z-(bCSUXFCq1jSm=tdKc2Oj~-R5zjI8{!c2gRXfEg8HT+GNy)yE0^*Cv~ z+QOdE7Ub@@Kr=)2();nMHUEFdT+lJ)%^b76Bg+@PURO>SdOvaAA^B{`KO~TJ{onxC zr;;h)bu8`j+?4H@fNs6lSF$F+lH`SSIa+O;ejt+4_G#ykr0Sdi+9aRqpzy(??UXTo zZ8Gd6L$4Y5EINUX6q=uYxzqbn;QO8>U+#39r{I?*n`yEssaRz^KJss*_0vwIv72pe z#jFb)0_Y3koCB0Ga+fD>8uHS~&Rq& zR*qXlK@^1A$n#Me#MybT``sew!Q3gsk?x@G_Qs$&2N5#kc-k`9ULBjd!F>=9RY-$_ zowZXRs}6;%71wqEJVdWUW_zXW!5|hYZykv{en(AcXj}!L6W43e4_yso53f%a%tC{N zn2LxxXwEU73@}e|M@;kSuL`k!6`688QO8aMHg%?jTW=V9NoNV{L$JX&_2<7 z*>Spc^qyWK@w0_KjKgh~|3BbIA&uqTCC(ZJyvwC-K_V+k61Xz2gE~O+gRc z?2~NF_os5d%kd)Pox`uTuU=nVIhy?W^}d{?t^1DB&zT{haG<)9+@K{DY!zi*_FIZQ zp#6%z*E3o3c;bFheSX9{!gd_5j)?m)c@vc(>t_GlO*4}W(9n1H^Qp>@%(1~2e|_3U znQKkS;>K%GJyJD>qn;`oq-DI4W`74QHSpqB#c1{o)8!#Dr?%pNZ;ZD^*^oPQZvoqA zH>q|ZzdZhb6u!WZGqyo54h}w8t*mtp_U=T3mfaj%QA$fU z|EpW?=UESZ1YPSZ|E6#EtNiYN=W1_2e&gyd@mr!1PC}me?m40zfk2DxcoQxj7`G{c z!W*K5HyOP@lJMm5{(x9SuaRAy<${LTlLQm+WQ-I-GEUyx^@hf^@G2Z15FSpEc%Xnr zFi|g(X*IBXRz2aQbT_ciLgN+Zv>doDgc^M1jC8vdav7* zUpj$ySeI>B>fo>5(9;~XD0ukMB&1D;Q4M3Y{9SBRRy0ypA|2{!Gzz%G(N;ftJ)r&Z6utO{ZQu1^(NG|?T#+pMsw{J*@@j)J<@TYuKU8=j| znuraT3z+nNXE{-fSn@%cJ6uw3&ib8|H{1@d-MI_};+ctzH9XXj zf8ak=fQSp^AdwR{3wOD&4+l0Ld)V-x0nT|(+4zvwp3DB-rN@Wt*C!9lzK&jS)Ddi; z6C+<~@2Ke20`5KPIZE4l+*8y~NV|4W(~C1ZT(fjM`*1gu(jdh(Ek&V?uR25TYru0; zzLO#KF2jvF7vJWLNF<>i#5K+*2GFz4f|kHm$ASdSBuAY1-U~lX>;J-7+le1Sf&A%h zZx4(6SKiETu-Jf>ZOe@du{^olvuv|{xok9FR>I`*M;HMotyH)1;h-CG-io|@wBUkq zkJ<3i$!a8ehZkq>D;6v`!rmj11by@#$WGuxtr?6~-e9PNA9Z{Wk}j6nefd<)vb?lX)IZ8F(K zOJNT?&cs06lT@b|o1`*MlnXCC+uk7`)4XP}K1t zJEoe-o}Y+vG}5WY(1jfxZsp>mwSe7PAM;+ zJhVBT&fc%!MN5rMd|B_7^VJSsm}~%sq;5b@3{j`2cck+)gpJQ_!GR<8-b6>sUXGs$ zuTsC#F5mbucGHu@%d^X-2PiF2Q-12xsWcV+_0_YV?LFBOc=PD|L{7({!+!tgPX+6{ z@$b{Lem8nr_%=LTB(92|x8FDwrTMu^-(``2Ck_xilS~{^@~~18jrQV(0V$wDQKpQy zNpio*@x`X&av>p@jlr$ztASa`vLa+#tH5@W%(9e2`60cR^vq6O&%x$Au4aK9*Q~q% zU8C*VmeKt(Ehba&PHz_Efsy3c+a>odu_*qU|DtZW zl!5!nt%nC6s%Cc&4Yriv2xC!S;0+f=vc)7e0W<9{1KB81y7{cc0Tg-D0SwQHH3ZS!N&!PO6~ zLEIf%y_WoWW6Bz6wh0mA6wrWgI)|6io15A#x1)jvvt;r<;Pv2Vm~)*3L4Fjix2gRYDolgqQ<-sfl@Z*VMi&k*30@+opJW+N}_TshU0;YP1BmrTl zRg<+9ASWWv)>k08L6`5qLSf}!+PX{_in0vbQn{ZXmS-0c4;cBijxkVltIiCYZ~Waw z*+sv${K)suIlb|172~1q+U5-b9$Lut^D|qH5GM?Y_EVCC7up~M96k|y16%iI-F^zA z$N`Q&0!APN$A_~#!o)!ZM4~?>SUIaLtBK`QO889)l9W$mKN(eZa|ZfjzL62a zxEuQoXQMVk?)tz5n41=lgXzTxC? zPm<&G^&0UWEm*OLr+@#vG37)RwaGi&wC+v{T53BSI6+TwBHvSCXdpfPrGTam1_3r} z#~&ASy<>vCZ{YaqFC=H^==D|_7|)?i;#;)j6s0KqFA`EJ;(yU+n6 zQBC2EI|PbCy~~v|?H>lRY4~G-wH{v>eBhwQ#T@v9%=apll=LBit={81O!J=ny2j9j zYxT`CO|T~@8Rz|=p?2?()x2fF0bL$?XF(9j#j$`eO@8bhx}1Vo`k7gpQjJUpdVImB zT4|9Xy){Bk5lxjnfb|`V6zI!M2XyOwG`Srt@|j2jxc2@~+sC>^|FMtg;E3$|sehg2 z?w>)AW!AeTf#4kkELq)tq2wb3eGYst3oGlMI0^-9LPAADo};`h6oQ~TG_z<9#Ikjg znaZe3p94ewT~;$-^WG|Y!-9q7tXTC^(rd|=J>BNayaPpIhRa4*aOqO^y{mrC9B*rI8_K zCkga$mD0*isLD@`P@wnm#N=Ci=vv*$JM`l(z4NL#G15#!{s7(sApSfq#r(e)E2pTq`2cKY-sW-Ts^Q`$NjM&D_>OL5&)x= zGlh41Q6%d7vK37G!$39-KNYOh_MOm*&6e7oU&;I*?%WcbB3c$&XA&vDZm`z*HvT~p zPT|Rg?+px{iRf z(q)cOy>A(B&lqPjB)qBsO;ywMR7?zvt+&DFNF_M!5XVZMJFaHGjI7m%;RK&^9*{w0 zrf?5^I}cVUPd~!5chav*q`+?LvV+wNy1P$e*17lQz7JJo@W#w+-207laA8IN!ku`r zR?y$uptB+Mkoo|EY5ec~4xj<y^_m`V+Fi{W|wP6T*b0Vg1i~JVhPih2HmVbgm(8O@O<1ih;2m20iZhqKte3)QV$P-=dt zIKVadU2&AplKP)^vg(y%X?*=~(CSClP0{XQk;X20)n&jK67sBDIgp9(aB$VxF9R?Z zO*A=l82P$^r#o>Nb%b&s>slozZr)yZQc&viKcNT{3!DQ-Ep^wA8th^Pj_eSZ?ep7} z+W{jawS0i$4#(AH6TOkU108?r4$$|M2=+$c4v_mPf#V@niL(baJcY@>eT@$+6v9y{ z1f)Z`k&C4ywdCmBz<4HmFF=L;cdtd3RVn!6&w6qb~-iaI`*KWu5t$ijc zEnfqO+`+G&qg>d!Uy%s)HXd&gOmzU*?}(V9ddR`8Ab__re`Cc?{cYB$ilDpiWgVxE z+4BWjVM1oBcdgBqA>WLBqu?cH<*eEJ1b9uE*Wb$8>(x_cd%rG_($V%Cjg91fkj3&) z5mX22*0V!?2)!HP)4v$`*zBFxRE4R!iU5xsYE#ajvmIt2E>tvo54Ic+;8>7U+DwI_ zoC_sEmk&DqMGs%pwBvOGh~aHn0HpAoXvLVt%X)m9a-?z`0PFNBTLpzM`B>?NOV*vdFNPB;8;=p zZ)a`Hormb`-Kjaw%urg^n@+lJkGZVYS0mblQ(uC9_S77zW&|2<7AXBLL2vJo>nUrL z_~(nw`WIsKx4ma!k?3tjd?&tzIo@{U_NKId>D@vsoVYUTT<`>MV{dQ$eGh(|_XHU) z6`hnfsuk5hkz2oN%6givFD{xS%eGouVs;KKYc=^C>X-XGE4jY0R%`}$?`40_C7kc80R~|1+u*`Eknq6I%;{9IaOF$Jl_BFxGt!EDt0++`RAmxd5ylgqJr*yVUHfNObA3GS=loHL_saM>y;jS4N9Nr$La7I-Sjeyu;n`EyN#~7}^i{*hZ{uR@pS{ZS&pNU(cZY*}91$ z-$!e7g_iF9)tx8Ct@}whbw^QMJ8RsViB6tiX4Sx5sd`H{&TIVWzi=h@5oWdvXD2_U2$bs{|_!PIy@V=B|#dot#A?|BTHKvnNaz?)#b zZ#N;?l3jN<-1xcols=b0h#}k|DlOiPG{YZvqtTL=HKj&6dF>A*=bDb&elYxJYWB|cC> zd(+EG4t?R8CF|4`{*E#1N+5;D*DXvy3Ah^CJqVT3`yj?)sreXn-RgeJ2#kdQP731s zND@!Hh*b6*tjV#}CS4DgL)~Qqxlwc4aicqYS3LKw-02+Y@0O8A#JE3&O0NkFj>H@T zz@-I(!F!0ehr>UGYCQqyP9Ey>97Q=!FEV&E$0@yIvM_UMk&$lMw00;o86U~GbYH-dxWT@TrEhqaiZsg#D@eUrI=hK)rzPHfA zm-rTslG9Enr(Y8KL1X6Vy~d+=1f4AGeeAO=Ilc01bivJR*x_K_d=^QjK3r|R-7+LE z+M)Z7SrZ0ryF_*DJqdUbz)2HC(i_bOX$?2NQt!@M+TDOF+&FEya{OCYf@Q;!LwA?| zN4A9{cG^eP&faOd0RojwSCXsVgwl06<@i9bQ`-{^RP z#BY;Q_as32_)GbX#|r>wS6=>+=$s(&%=D^!{!1-%A~}u}JHpU2O4i^Os_;db|@dV@EYf}=l$1lnZFMcNE z6V3pLr>~9k2&7jai}T3{!+yPG##evcYiS>NeyZff4NEN7cBOl#{C}WpwWFut3In+Z zxB{k5CY{bSwn_`H8r~&8#5dzpVvM)Gt+dW(rg1!Mm_GZ0#@@pDvIS%IpPD)2n)u{H z*LID3XCjQeURgC<*-T$nDCa2xa{$?2fLuHUldCiENe~R2(%MwGq+V*|9)--2H}$wV|R=R>e|zkAsZ46W_Ay#2|n~Jyf>ZkQ#z$x79wnRdf>H9qOQTpXBs| zgr<8xB1G>wi0z;-*q9|Bi9gDhQkUZXK5||+x3SjPcT9=TUXmTATOJqf1W76G8pFp6j8zH~&vI9dXmfb6+2S zq4?(DXWB`!6Ai9;$FV<65C>nOto>JF7xGxWt{g%o{sf8t*1;PGg&$2`CZ3p!#NS3S zV&mF1j*NDf_s6giH-ec#CmS4p6-P^)xg?VR?XTeZc3Ow~b}}>qFnHs;n-5P~xhj$P z@r=lFu?%sg-4b~N=pju;sLL4$bAg^I%MH(W(F#W<%9iF#boLn!t__t9_>91JGvEzr zuz^zn#y~WgSj}m&eIn}7IfC-N_QoAc_0R6uP=^fc!!RFdVX5=eD4Kf{clAL&nPrIe zGS*v2b*kfCOk-n0J;B_`LS0@_08Ogm{p0^Cu8A-^HPKmGxPd!0bJ{X+{)(|1{s;z| z7-R@VoBcBe1hEe6!y)#OZN2Vv9^k2W`sLZ?B7bo6!}ldBOrS?8{=>gL{k-mo(da$2 zrT~kX?8HoMPSL&Vy}tc5ItYKiq-VxR`2dXdPOx=Cy7R$xxI>-+gsILc*9WK1uj}mX z#BP5)82bH{-#6{eOmlqj|NFQRl9y#qz%ZppAB;Ex?vrs^nPjsmQg4RN>uWn*NJFJI z{=|{`!R&jFglGkAm!XNImFUPdCF0{uz5~F~LO&8eGZ~ps@_{}m_c5W!6ciIRlqd)F zmk6CDKFVY;i=RA~F$Q7RjT0ECT zml3bXl2%FJEZzJ;Q5$}8be@*dh>iLaF&0Y&D&CUG+gsc<9&g+ z{3(nd7qb`;sS7MF5VtslI-Hqk^HY+0BPN#%m=t22K1_6imcsDv5F$|_RX(9@;O3Wo zk=nTrNya0Z*p)k@G9ypr{fZrhN;c_G7P7n^VdpIo-rPyd)yu>!SuS((*Cr02+oT%S z9nQjjcx7q=n+v`zyZ`tfcfFv#V8A*Qdv;iDSlbOVlHOW4^5l@={&y4GQ?#L<0|T(I z%4gDIPYzdeetXGcX=v0>BHQf+w`p_+{PRVM|I7cL{!xwBZ~vaXQno=|u|u7m($MCa zuTF^$MT-(bVKW_!GxC8!W*fd7y-zN7T}eV74i`^%4#+af6x#5<>Uhwqz>I#TP&NEw7;Dg7SCLj9cKN#V3S#% zG59A!jI*=%JBj7o-HO`=2$KhS9=Z$D%Nm@v?=GQl)gOw3=v`vt(kxWe=}C|BR*V28 z2!E9-I7w(>&@~U&h-bNDNcGj+HjFdPy0%kGyZ%Sf-Mw=QSu%kw<%!&%h+9`3qV}q& z?Y~KipU16JC1ITv2R4<>boRa|_xIzvJ8~XNO!&uukl`bAnr?~rO^{{pEZb~}Mo}EH z^d5MKbr*raZ`6ULeS~gI;txq$$SpCD9WeJli@?a(x6j~hpR=3=+{4lbeb(B-5B_ze zcqOz@RWP%2y z^Q40g8+|EvIB3@c9nI>nAKZWpc+|z_Z4}%gp$BIs+hSCkYJs=6WIuoZ38Op2++oe5 z#yM3@&1`pGm1;@|S`^-bh9*YpYtnv849_!TRrV{3E#-fJ08#8kBkG-gng8g~k#k=r z`mEU(QaoF*;0CpPH^^+jLyJT7-doJn=AN(Cu5VSS-cL+@+_q?E%LnlIX!J8O8h1TO zmONNu`zF6yI`wC~ZMNyf9v9=kEU;1Dmai&K?l+2CEiMNM;F>b@-fHs1tcxB#&lA}? zw1CzSndD0n7XG0Jm84-N z(-}FK#c`I$0j18lf;(W{sUk_*=emo-+&aXi{N|p!B^s&nC6zN5bs)u$?5&<)#KPw+CzGBfyzsc_d!jf|isXljcsrTsJ zM>z;Yn(c2yMWu}n*t=rP8Y}jVJx7XfE?{xG+=~2d|MrI8F{&+s$W5@FC%LCj383Yn z>e)*9#(VR~WAFy1vKCj5O2`5j4k0^L=zYw3UN>gU&UV-O_WR*?e`B*8pRj&NuFnu7 zO;ntifmo9}OK`llhs{RaZxd7=7>2*D>B1dvKd?6_koKlOpucW&0MBA_)elV&dPvHb z^41z_U_+ogP&XYJrnFsX%-)LOTLtP$8*UWXt_V_+whohXq3C@;=j__W#5ETd4u++VFczVFUB5{4%s87-I;lkNk*UDWf9_y$mvdNG#f=WQ9 zJRglCH&xQe8qp)}Mc3sTG~6}o9$4629qP~aZPZ;9HATBP6)q=|bIX`)B-@C#MRYfA z1rmqO@u&~Ai)e1w`Vpy5D#b`|q3{j}EeBx*O(!h~BnK9`gs78L;!Sh0gj}vV|8vjW zb-vD?UvtNNFo)VWVfLcj?j@f`4Bvw+dkAlDLTa*LEU=xZ8tR3u7+tHu^=^K2gd!^zAzA==aqdntb+-Q~vrKcPiK4UKDM8Nz`UycSrAo zhoVt)HTq0>ZcRT!)}0!eEPyKSoO>Sv0!9I{p-H8UI=NyAW6+IrI9dc@R+%Xag~co- zU~sE;D+RtP-a@zs&e?>^<wiVw^FH1*mKq5g``6%xh@NF?C%e*n=LlONygGv%=i`{)qc^}RBT*co_6qT-z=Dtv=42srbE zE$f!-sEPL!iRQZ{i}u!L(+YucvSjS@-WC|_dQY!{U7J_5!05->&%m&*{W$x{d)}p) zn|Pzpm7F`=G~O{%1msWqNf7Bf`f5MgPJf>(Nb6qHwo3qKK$yQ;*J1C?XI)dbHVwp8jIsJcB@<$Jm!gb!sV^XhQ?B?d3G;^ySI-g-{L*F#%q`0 za@sZe``Jl8JCO;s3)o!9;Pes-ljo!Iknd6&1F$hVrGZ`N%AiX*XZ_@H z=QNVjzjE3~yEHhN@pL0LrTfwz&AK3(v&QX^^n#dl-k=Q-?!}+;U|?47W(DO5Bd|Z}@r^uy)&spjdR$Gx<$Q8@nwcdn;KBS)9rIx;Y9XM~{QQf1*eDy6MPl1oA~* zK=^%QxP=LJbL0DWEmX|H7Zck!*|C+wu}5h zlT&(+(kkYXw~^HJ${s2jrNx2M4rMQM!7a>x+ra}CXNEcla1iyXT5E2Uk~m!Y_Bh)3 zeh8QOCU&atYUI_`nT&4ILo(OfPbcP>PCG3S?BfPkz&U`>9d!%5E@m?b z>3C@>(P>`&o1Mi=-qZo9y5)afxD)2$0fczz>&XK89TJ>kWsQ7{3J zkn&)vU2Jhjab0OE1geG6R`eE4$wlSwrBZz(~Xt}iVN1hoU>KADus9E z>4aKK3R>D;GC!}ly$9p&=*khzvxCe9ye=>3WA#hXjizn<74i<@dO!G70;?P{n-CF! zCYqie+!~&*5G&5A3pCIlwDyE6i;Vn1lhYzkrOh!Ln>gZG>s&aSsu#VlvU8LfR($E= z38N~g&I$Zwa`@bIXL@pv9_e+AO2na7Rn)!i4z={tqdz~Te!(UO-|=?$k}!D0-B0bt z{MHNWp7hsWpDw+HtzQR|VD=(FMY0cV%-+vd6*6S(**P%i$r&)n1on>l0rp@Oj9luN zuAFFtxw~mPa!(~MkcM)nvM&0efv2_S(+m{#g~}pVA#W5$Np1x_>g*fhIq9K=W&9QLK%FO=J@*OE9>*nEMbJdk(}P>X^AiGz)u=#& z{?OV34k{b@LzB}Y?<)u^dTC~okV4s)icr0p?33)-Wgj%Tz-Zwio+?o10576GRXdu_ zL_0x&Kv>6f|8%p`9qxXB+|3~R``v^Lsdp_P@MFVa4dq19VFU3JI`wgsiM{{%uR(?| z`*94(zT)h=Z3D8PyRba38f2T2Rk%fM0Jg?0cUOcKHX%?ix?c&rH5UhjS_@RRh#QHH zo-J0ee74ldYTYc~l}ZAQ$9cmhm@2HMT}BK#+pt%>4f`!j*h&lkB?Tv;CjKTBN4Y)t zg*?eQA=T8}S#sY6@dghpv<9T(HfruZw;L3=Ca%tP`+7!5tl8)Ib5Z%E+}BA5#c1_fGAGTf zeOH)i<*e+qcN$GUyNUaDv-cjuAOL2$L%ca$&sw{kbkXcg$KD^%;!g(yd#?%w&g6;h z3s7r<#SYk+HCN0ye~}Ht?XiDHFm3PNk!g&e*tI~nx@=RY!w=Jiji%#D z(J|!&Tp45L<8ILE@rL(147&TShRzG>AmOUC$Aw%EK>!}ez}=9x|M}TV{4np$L&Jl^ zKVkvy1Ez!V_gk6$TvA z;!w)uP+`Ja%uM7E(yqjIu;7y2+{wpvI4Jg=qumUBPte>Ys7=`QtgeZ2SQspiCSEb` z#nVhWBIc^pq1WY~k78rX0vU2N0TfS$_X^soP#tOL-rW{GE>4`EGCJXWsk<0(V4h#{uqFLKd;V44^*I-OKWf;4Sv>ezsrq_lOpTf{?p$O=_SdE)Ugbzed z#4Gkyvmw%w2!&Q)qDgt(H z0Vo3i9y-*W&Ak-A6H!~g&-MWQ>ft5d#&zq?me0-^@+GS$2CJ#Uvk9hoV2gJEgfQG& z-@cN(VMB*z9)_IZ>hjCW4z;z+IK=Z%HdD1{p>oig@ot16$|HptA4iK1)yDJ=tDE*vkD zp(h>PdKzs;cuI9Z=>7rSP7`scoP*O|u(*{CFoi`T+G$X+capBK=85(4G-VhBxDe}h z*`Jw?6MAQkp{E?KlZXtxt)E+{2aX*&o&*;UKN!JY+_IZaIjn#k0fSLzoFho_(#&q5 zS_&pUSn4C0?)(laEAzK-*8ug^x+S_CXShj@(`2L`&y<7lqIYMZ+vfB$#Jchu2Uy&0MP8!L4q8SkOtcxxF29B(t~U;y`jf5?|UeBi1o#k zs~omecRJ`xj|d5<7=N}@rs76#id4#;k)Mp8dA9 zSbN;Oj{es8$A8E5=ewj{r_Fji&$7tXOy4BjdPk{a<6j@0ATbB8BduH=1AukRj}vaS z(7ELYTi)mVwwE7#XPn~b$) z+yKBOwNjTy(wM@k4lUz5V8M#6k4atWvZ6qk7knE1iE?pH-aI;W%J5fUMXON??`}b& z0Zt3Ble~@Xi{((rhedtXKYAnKNq~`29+k_VkvaB0QrK8`&TWhV>7+|!pJL8?!%>ux9`BpoHM+7e?u1AM zxVyT)%(Dl*rT6b9@+%pvo9bh!9=TX{X8#Id9u*=6QBd`rGs= zp30=*_F+SAd<#-MF!IMK3mAAT18`eXHhfq#)x;XoM2AcXOQ4WDG>J1crcc0&%fjlr ztgcZ$#Tm9)=xy0`e~O{oNJ6x8=jhr|cLd!S9gj2{@ev*`a; z9u9cjb{gz9QkXL#b0Y)=>K=*GW}3-R(XBw-gX1L6M~{3;;i>D%mm}n-d-{dDJe_y? zc>yvvwevy+d(4L0#M>sfW2cdRE5djW__e@aZW?g(*#vR#RM^z%%pG=Jha!0DCD}Wm zOtRQ(&>2z2jmNehobx_*9U!(cI=JS(@y+%wz;lh6{$jM}bPvu;*9?;4fGkhF4|PU^ zP2XLDn(BVht3M%K32opNbfF^!<5Ypt<>-ihc`qVK=c$)N81UaK6t^$-PQAV?zr`r< z@Z64A&MU*7EOIXTKy)<=k|XhTl0COjzxyZQCJqzSAl^P(M) z1dgZ!%}h9n|L4_6ytjdi2pW0@Fjh19@C3q|n>er5dfrlSj`TzqJ(=5ATBDv4OW51W zn$77Z83K?Ne*WJX%g;rKS$ zUb9+s(ml01;UK%y$sVPd+<#V{nK0&07h@mqnI}Xvxh9dA|1+|rW~EslI0Wf8VIOjP#p6@;3DXQUj2sZ!Y%`^AEo!b~2qiRC@n)oN=EDjE@IOH2 z)Sq-QzI~}Qw*4+}Tg29K8;DRW@2))lBc`VjZ^r znSM~$vU&T&+m95dgY{eXxEy-D(UUzU`dz=8_2BODu1=H5)a?bDGgPEtAIiNQ3aJPm zxV;^UzcZgjltHZEd==spNIZtLUk$$dr9?S|M8?OMiCO388*Cc<_N0uKT=Fb~;K2Y~ zYUd%yO^d~_8J1MMSW2^fcnwkUGZ5*Wm38=mvn2yCrPpr5G+_Ei$*D88&}NTakF#55 z2c|Y$L~u9< z;KigIAj)tzEF3~st28f?_PU>TSyY8imy!_Qp2#Sxu( zENJMx;04^}wxnsDzZ@r{F?y_J)a=~@Qg;#Mkk)cUeYr28M4NLjZqtz8A;QVwnZXJY zWpWZBQKE4S83$_au0=raYiJNqc&AQ|YNY8h@Eo}OHQ^nIIKM-NkaIw9(K)f8b)!Kf z86U|w0R(X;zPzA<;JNFh5p1jiIUf>C!tG$Wwo4IhLu$+hc2`!;VW-nhP1Cq|%U@Rk zY+K{xoJZzWHFV9T-lA68@ZAZMbVfB7TTZesqb4%VL;E}p5 z=8Q=DWMUXxzKLra6h(o<8bLW*d%0LpUYSk0QTOb%%~HH|&Xrvs`~J9Rw5Yn*%m z4rldrb%mA02gOj*%5M*>K&4wB6$VJsHZ5==5v&p^!M^f-%T@fn&($kXR z8judT?U>Tw`W!vDEIYQ7+_Tk~npUiJ322o8aR<`ofcb350lH5$Eg2_UiKdTSUs}U! z`&kq?3O-Q{Kd6S*;ival>Z>Zfg)Wa-5@KIn zLD+ubi87M!hX*8=D4Qmi`RGD6a7|V&GO!4Ic;Ix5;_=n+sNm*CD|@XJ_nvq4kGr2i ze!TtcJ$sEM^crwSJiPa0ZK{fhu^?nM6k6Hs<#9BSHJKTSaJUyB$n6dY%s}U_mTZql z)Q5|vFN0Ea9t7FSP*<>PPZKKl4H}rctG>daZ$9?3C)~j8ZQ+NHcen4wU;jhb-r@G{ z?a8q2p6-^;Yh}3a#=4cqa(U*34|iABDlbf={<1aj61ur6OS-^{pi-b2((zMlJK*VL z>gETufZH+?v`d2z8UG}Ad+07hO*4+JX-al#cicdFc#`NECriLY26E(pTfkvcr>m=2 zOMHoQsBPSvq^}AJx79-pRIte{yYIBt8s3r3b8wy?lr?)h8g*ZPpTu5saVUBo3Rs}Q z(DT-;(??*!=(5anN|SK@bki2)w$5SlFI%(f_BY|6cc1Xr;?U1;U=P89{XAzfl1spKt7S#H)0(*FQNpM>u2jdK0Cpp z;*U4A;c?%K7mrPcF^89Ep z5&X)WDSn|;{Nf{BXt0iL`D`G{g9!>a?SuO zwKOx6ULg{2p~2gn^3|4$5d6Kk9ykvU->#dqNHffB#STjBm95Epq8j}Wgd2{$0t~xn z!<{3VMRCCzfXsp&^g!>arJ;|z!4FdMML*&EYFQThCkkzEC{pB=u_;;wSfL0;<45}X(!8C}R_ZQ*~txU)t5FuY-c>__} zW}_survx-ns5sR`dWqyvwT4r16QYTz8O(C*!yoI$p!b0p>tU@rUbq^`Nv?ZIH^#mk z_EgiqcSBvbrI_>KARJ%6B>lRtQF7Y!=^sB}c_g_+vZ!JYz~&vEBnx+2miCg<{Sb&FEqB5pdK}Yd3mlI*NPNqa#K?Pm z#=_qrrF&AJJO!*=(EX=S=_IQj*|eNsdEHhv2~Tg*7oSctK1hw|uZo!L(B;mmr(4)G z6ReHw3N@E;NAlkaZO1tN(!^O8X*jAqzAZGo94N;KIvu`Oc!wh% z-%gX~HF8}CXd*8T8}BAUbF+{Jv0|ptR|b!KQ+Wsagq@#s-IVj_9d@}x%`)wB(uS8z zy{sG0XLa2_%1#8Um~6C zeT>{YAPQ4GKmmh}MH^mZJVv7}=`Hh*B-F=zAV@o6tlk}aFPut1bi`T`=alWZIal=L zia4kxk$0WkV`QLqFYhiZuEz-u+To;gcyaPh%7szyYp7~wnZb?chuoxVp3H;Zqhhy7 zhB;49=7`Z(8kmOS2CTl)G3SV63B?Z905S_4uY0$t=ApR1rN*w_L9r`#8tf^F)dc(z z14sSn9RY3T3;4}U_p0L^+g^Il`YH;2xM?Ed+{>pX0V>QbJ~Et+UcKwIJwb4@2F`Ym z9QP{9vQ8XyPT$2pE@%Sa1(0&`St#w}1D}Kzf+h)y2hcRjc5-nOm!mw%ot_NUx0{!5 zl$nCLw>bg7%*%7(_W}Rdefg$*_@)Coh11@>XmMsrae(vEhI(drP%lCtMsRBvUI-8= z2cE{YVs`HN-i5to%^j6+AO2r0X>vb4g2}!-O7}AHa?*x(SOHKAO89wf#|tzr;!XA+ z78-9ZzoYXdk;z}bo=@%{KJ&4d9K810?uUdI&HZ{7?NIZ=`ZX9HmN3n1So!QPU{d2*AB8S|aqT~?e-L(?gzwk|^OP|PSa1@vdvOZKrqj z{%Cjt!A%p3IDb=s02SsD?^Ma7wus%r_9?(G1kbdQcT4Fb_lp$~kCwTVV)`xgFc6}tk+S=HG03o9 zCggI$Y_zr`+n%QeCGu~h8}jgkCgFIAeCo%e}sFjv@>_)2&Vjr;MDu(<;4aPN#&r?oDOXD z90%KjX%^*u%M{k*+*})pC#A>iLgV&5cy_N|o$ChIM&t43^ygkOhQ-ajS!oTe!So zI9x(tK!c_Q(Eu4T$gP)IWTC0E^KN(#JdW?U-UMaGFYzqxKzmdg6&qV}*!pc2)*X=H zjdv8iIN{~Prk4oN_5t5Vtt3j^CVL+c$`>O7=-zQn$^oJvNxKyK7DOKEi1_i7e6+0( z^jn#ngw<9FlyOM&-XHRN(VJP`uQohU%&pb1yHU1)zqM0a~0`t>^mWcR$arXYaF;drkJTS|iF zUK98o#P~Kt2@C#i)Rgyc-@@6Ul8i?*o1bKJM`rB%`Bc@3o7pYyZb8`w&P7T43>GYW z0A%yGcA#~WC>v>~N+Ih+>b#Jvu$P|))Azz+Gx6g>lko09;yXB-hqlb!D6R$R2Sv>U zO#MI(nPST9T9R^idVS0RbGz#u%^{dL{7UI-LC|Y^bINP)7-QOQm{@Fma?j(P)4Qk* zdv6+fVz42}J1#q#J}}yP`TSDRzCK!ZiSK}*-W4#&Zq!0)y<=a|$pc0nfw)HRRKTH0 z0Mk{|LvJE9R6>itxoELdNu!lA(;W1!-ub+ir~_*C;%sQ~eM_X?4FfLnJ==EO9^ARO zu2p-CeeWV!Ip_!MS2zy!Lwn(#Bes<~dI$BfC2olJm4jg(8hC!BO1y&^_s2$SuCOs$ zaw}+^y)pPri45DmVajRQjb2}&5~Z0Ib~$yo-1_V!H6Ezfwn<_6pF zPpu)Lf%iKf^&214_>k=E++7PiZR}OZBy$9rzn^8mJJa$EPMxBls)9K<8Z z9mI+3Mp1OyJz9|`dBhl|7~)#F%UCOS^mXgXVcyy;DOMhIyV#+mlXt#gDcRxhV+z}L zJAo|J`Ks@R0T=m@BTP9&@arI_RXZCfl6270;xWq2g5MD4iZ=$Cu@6&Nk8`;;67NhY z@f(M{O?iLx8j-MnhF$d@GWzo$WC5XI-0Cs%V#@2iBeNF<8Z51LdDGo->v_C@6S$p? zq;7tD*N`va)#EDfN1B>{kJHB7tHq(=5RpZ)`+r(f_8GS4sI2OmFBwwdzZ_NqS4{tM zdJZPIFI*nd9y1&I-s|HJ6SM{9OO-omOURp^2;3~%K9|+P%usNP8lm`_rLGEV3%@j?vFeur;_oTBA=;iY$Q z56g31JtZ&TdT)bd!A?1^igo(zSHBtl7S{Utp+*3wR|BPWn?doW@%zsnz~$ax z{n61N@jy9;m$6TzTF<1bsie|Lj~sctq#=w7K~hfL%j7F92~qci9?1-o*``&F_*Km= zhYTc9bwo-*1QQpy2C@^5tC>3u`!Q|l*p}hL0zF0l#hLq23;0%t!3@!NQclndhxRG}G9U6Z&R$@?`h2CfkK zyD!9Bq$`2obEjIK+N7(iWOUv7nn9ysEaywjExN^L(YnT$D4T}gVb5K z6)gi25N%Bj#Nf^N68g9u2=BGj!pt@AErXr^k^VUL+hMws`+W56DYB!C<<$);Y42s( zNHl}Em-|;d`>txBcXj@T?vdh3<}U2i`cG{@6v!aKo8<$oyOH_MwP= zW4ar7tkNO_RvRn`ct(=;{s9@jUN;_f?U=c7(mTJ(kZTjUgU+trXGKr)oLOLeod{&Q zI+B4N)8UNMSU;qUJI_7`q2sC?hyqr6YvZC}M8a!;2`g{I*>l+zntPC@{bwi622#BT zVp{VlhZ(>(ZH5NM%i_vQ7OvX817Y&%e9~0{fWNoJQT{bOo$*R$Js9}Ix;qVWmp%^M zLCDWwv`x%qTPBc?q|52XH)-v7A%=HLu@s?|E^mgVuab!J)Kpz;oBz(01is}8BX z`AwC-R|w~5^^>mHx(ll;HR-zKxb6e!%00UFPJQeRvz?$sF~J{UxBZ(!d1fLV54II@ zZ9g7Nj~UJO@Y3$?u&@tZ+nv9>nAxPQj}J^VqHWu|uZZ9u@K>@_7YTPl0&k;PreGq| zXJ)?r@`-ksOGTb8I*cO=ksLM4hn=*c@?}2!-j>Yc5?fEMrvQ7@JTPd{R z0c!O=`OenesXBP&#Zmqp(H{z3a9t-18GhIYrL||P?Xx-LE~hV}O)UQ{z@+hVDq_oK zUUD2SVz~WYegLVWUUc^K4)>`%U%qU~%(Z_v!I2CyIn+i1vfVH*{SonPO6e?P~*Tw>zv}=P0`G zvYko38Bl-x@@cD)>vZqY<;c1r@K=bYl*?4+K3k(H_T6h&%!7}X`S-p{!eaR)g*gnW zgPL}0**$u-_Q~X0R;st+!2-3Rw8#Ymt9iY@ez{jhOSlv1T5~f>-gq7=LrON^iHtPu z29sb9t#kYB0&c0Qd!O9lHRH}Oz*>mI2$IS^D&O6G_&JkpHamyWY6isbL4xm=Y(zeA z$6EJR5*lJ#rLO^p-E_ObkI$61Sy#@u%n)vv!c0K!bmA5FG3*Q#J~_;OP~X8(r&@Bp zw!_(#=gIHS2745Vz1P#>?Av+vulMgJnQYbK-g8X(SEBxZiV5VGsDbK1Y zbEJTszeZ?a0X1+sue=SrpN77bcW6*N^cHReU?eGcqlax?j;q!CECb9q(VO5=wK=RU zLSuGSYI+FlZ1Sbr+oixvz&R!Aq3h^^q2WXn{a1e4lGS^k{<9>;C_8*KXe9y+rfEVx z*|QSWMh#CwOQ9@)P~#Ai7n;VhKe@ewK&1p^cR-Q5I%hSnl3-3;llF2Lcm)B1;o zaZ8-XFGiqv=k387cj0F8i{c6ar+Vnxd-kbrm5v_Z>x72`0XsT;H0EUjS}f?xi>|11 zX%t6!AmzJ7h|fXC(E`4Wwt2n|2<)sz)Al(G#ckZOQTOdfAPou11#T{&JAMb*^zb44OJopH(b1=ci^_zS}l$7Q3124&VM00OVSrrvG zQA^B;3fQs9n+MI|$PMB0Va*6M$8xTRz6Y`tLia+}w?n`OmM$T|bpR%o^OWbu&YTQ& z0S_tAhjKDOr@)WqoNH5Twm0MA^3?%+;e7ot>x+CIhDVIld+!05xZk7QcDoJk{1xwb>Jy`ljV~Ers8`#ZP^fPly`tO7+53XZ4r9~EMPCgB zxM9`<>{7KLNP&0SZ~((EOMg#18l@7UP1RvHjTXjG@5EK_B-QEC+@W{8gWBgu(=qVI zBC(Egh`?w%8l>^;$!y#1g)J|LH=bSw_bAfF$+E90-M8nsAA7eMMr>$lnsDrQjhuLB z268tR!!n%2G1b?UE;o$wg@7){v)^jq0Mz1g?0pCFQYTA=AO53y<5c#i-o2kALMH+z ztI_-9wZ=CyHYm!QT;V_0O_uatbw5nrlTphIwl#kd z$_464|FakhWFAMP*C)AVyO!+0vV^|N-t~@7Un^G;ArPMOb((COxf^X>Im29hOCyN{=99gi&CTA>A%fhqcQ z)WB1a1AYPY4O2qUjgrUx0N9Uh*?oI%NOP)lNMVA&V9#*UC}T!;_p(LjE>GT*WoZ(=!r_RSJ?!1@{t)cTNPB=BCP5hqCB=^W@SOr@I~& z{FT9W?@!p9g5L=4+jHDFSIIKt0N5VTo(SrlmVJl(cBWGJP9oL5)tB-dHD!(p`1R+A z1`ePO*CP#z9JKoKtAbhIwG|(1`LRkHeq5_8w2J zXFo$qNWCq6N-Nlv*9-6yXcwho3XY94SR9zuul9!&zyPgg|k$krdLa zTPY~U&}+)8#5V|Zae`GN5)pB&AhNdWR@X@5y@tr)s`!zs1!IkuSKD(wFCHKJZbp#i z3G@L|9T^5!4c&Kjr$LN+)m@Qxvc$fxn~X0JY@nQXuX>yNz4&_{+!gSp^R$C0-<7+5 zwd&tEm#zE=7koK0skV+p8B`T_nr(3(W(Q`p?vAw@z~%^d^2!L__tS2KOxDo3vajWN zVZf10!_my#=9_TIz0+q~RPU%qHxMGE7`>V4sm|hcDnqUZGzLQ<3<6=lT60S z4vG7X!wNUh1T~oqW(Va(c!Bao4`?WE1&%zc5C=Yrt(v@JdcExZ%o6UiM%pqz{*g|>@N^pX*7z0j~? z8?yv3-)7x$D^hCF-)gI|oq*fY4!^BhTZDR}c#)4AkUXk#CxRM)>!LX%o+$G>JlRj4 z0vQ6GJ9S{4N0%EECgBD%z&0Vyg3MWiODsYb%*jbPp;7TEv&_KAI-UEStnuJG14zK_ z0$iNi!y)C(^lhjUq)trk?BSqn;pH#-?Lca;6VX2IxAEoF@RZB&iOWYr z=Qm_BO*EY^Af6@nW`RlF9UXPtZw-x4^-fAkW7_1{ts>-z;1~g$%CV z}E9lV~-|^?%TiTb>807L5_T?ev=$~=lW#|3|?b7O7@c!ifGd9s} zvG+)FzkOVA`3(7~Zs$GIr4Vcpg1e(kC7aL+sr4%FGQdn?lprzSAdvgk_duHujlu|} zilF_2;KO^LQF zq1p=E%Gq(C=J)>ZUm&4o( z_lFQg7=2k`4O}*{xc5l*g!0&dpA`I;=f-o2OGmv3=Qx*)ebCV&Mem#HD7N?>ubK%9 za(gu1u6qg->hSOJMJhcS{w()~Mz-Z;O~#1&yFjHkWB)$DKElNbu1CgJl4)EVHtINz z`n~9lQFr_i2??4KI1*q;Tdxv27D$>Q^m;kXpm^hSFh%1H(;h{3k0+nE{fR^1FrMxu zk_e$mCp@8&Nx29B8q))Z8VWv{=-L=LhabI5N>pxot2&j6)hC+ay77vYrv6?x1i;sA zxoJW1L#-sD$mZ;l8jU&h__|4{LmqA z-;DcMb`J@6h!k(`9Gy9L&>taW827C*&5lU*iwXC92Uhnim1oZJh)|A~{33RpMQa3%@fDdEdjeIg$e ziR^e#+|t3Y;PlTyv+Gxau_j97Cf(G*;fM*tIA$Uo2w220=bY2odTYn=-M4qI?OwZP zHsjxk!sBfz&wOn1q4vIB@P4q})?{wi+PujA`3e30W8oQLePfEx4~-Tk0@)Zf6Enm8 zr)L@E{sL(GDGG&&&EiDJ%rU)rk~`hAY&(bZCVQy!EO)|%#Aa!rGY=P)`p%Hpn7u;< z$-b)%)iOG28}nt4MmiqWe*CH+45T&tUJ#%y@@L`g@y<@Nyp+*RcAh`%z^@ei`{Ud= zti4iaIy-(uDq|lyTBPXxL>;R4C<`7<2yp80t?_oS8a}&uekQ4 z7TeLCgG4>Z=qt>H@%iJdlH|U@@eP$5Ee=AwPqF+(*dg*(6Pv@E|Yb_qtj&FU9hL!jW)K$j`S?zslYT&)oUYR+^N(r$YyNlBZ z_z1*?*->MgD_~~oK|Kxn1G4YF7l-2>dh^(jWJ&*^>67ufVYpmU?*}>rUp72dbKlK< z?6C5mBj_I7(>eEgcg)Wl7%468Lh-KQ(E(H^AfU|L?-VR#exam7q5#7btR8YCp>EH9 z=3b1ee|)b-+NC)jHO^?}ev4eb{Jp0TN6Rk)dC;0@_FwQ%vpr#bs&@~H3v7J=SqKdG zm%KN?+`DkT$S$T4LeS$n%*#OA7w(J}J6Q2UW%vXJ&^OF`1N2VD`({*JI8nb2ihk95 z6SMbMK)H|L6R|46J>S+ifa$U z$#q+dEQlIP$|*J`0;mLK3LPjXI9&zjI;u_t9dpgu!!p$kdkaa&J#F;(9#Dd4H?D1R z+G<$v_Bzx90<4H`FIBgG)PO6Qgle~<-&V~)nFN}eYi=tEJ$s>z;zf-uD*;Fxv41^c z3810aqRbURDy+5~bvNGNwpeun8QtO6?!YW4qTwST1+$@G<5gr-H*WDLHw2L6#EM3e z$j5a|M0Nve2R42UmAV7hobadaKs7#1MkJ~G#GdVh3e$vqvJB8DY|Gqv`4m=FRl~ad z0@38;Zd=1?itHDHJdxnco~c{#v&e3!a@1)Li5^lihNX|q`O^V%TQt+nFHp{SOP4bV zRCmCaLY8u$&2{CjH|Pw zm>3XOdVo$YHeFOx#lb^AXmWdzAkJ*7mO`+iR&;4{d+3it)K=os=``YU?g43F%kk$z zO4~mqtW&+dYRmtgET%?zV8=Bfi_JkpV!nDAh=r*|)Ee;|@5=k?1oKf2+F z?@~|m+Y3)`ZN5_FgcQ#*20TAeg`HvwbtK8k_rv&h_))R&Jb5WN&U?Jn8#vv($4B|f z8^hkq<6?n}y`|{yK$q4MwDQ2rCm_+eX_1Le9u2lBXXVJ^ z&|5IjrMfyE2w(5u+!;3%GXaEfz%DrLCunyAHD=Y8q8dHlwdh5}c>jfoh`7@_bMh(o zb~v8Pv*(2({gPzUjp=;pn!L96#cjeIxZoGJ{J}`=)Jlg{kwQn(xB4h{a*I zkq&Z4d>C+6*ao4&BERmDxmNBk{P8-%DY1zcMhT^+8v>vu&{9xNm#bS7&~wYT!|8TovQErM`du`G$P^|*OdcyU$jO|T~Sy&+WZUgzjxa^|CM?y{tg8Pt6b z?rV&D={~qa%(>(1K$=NkG$t>YG_80 zHPIbF2E4MO-oO!im+2-cDW=#ET)lHsm1N%AjY^20KvwZi1Lk^h$oPC}K`iQB zj+~{I1kZlC*9#)b5h0e*Xf0^ZfCB<-X2RH!Ps#G?$X9PJf!?7?Bvy2+apNA#%-zu zl9U^?KELADt*W>?>h@M=re0M+^;pP^PkZ7PB5n^^*(s_pwx6+0Z$Md62{AjYBMjvZ2rPF@f z1S^h42W|#9b?tj(8j%i?nzxsQyE87C@+8<7L+0@a!oCNUWjRCa_xiJ@Mn$Gkr=(Ua zyZR9727FbKJhhU7J?{);h!mC$j}hE^sc42jGP7o zL+{kPCa&qPpW<@tn|d1)-EjmoUwsirZFg$wot2acY|vAmw<9Av70zbfBgmKD&r9!! z@k(n`XxNwclm##!MS;tex~={!)}-rqzHuBv^>|Az?X5m+z$g z76-B_79A_BSI=2c#Lbj@7&j2ue6Qy7h^GthkdSgOM-CDgWAwgl(}R7UBxbF=2&K~n z7v4$~Yoqj(LNjTTD!UOPGQjSUZ*6pK4wujnX7NN`gm2LMRwx#e8`8S8J3B|OFcLT@ zs3^Y537db4h#w_^TR{+>sR1LMS#wF~uH31+fjyHx@i5tZ@J#4;Mjm2V`>EaO*CFMt zm7&D*7X?~kvQa4tP3y-d08-^@#E4~34hLYDpbtsy9O5os3wPJJHszGfB5}UYfG$@O zob<>WBhJ%1zF3M}6W!du-8F1!WdQ>3xBpU}7)HMwca1pP?pFl$4l0H}&8*q!xGA-= z#5V==l(W9RwXm?5GTJ^eKOLOK@XyOs4q?o1ReomA@1W?tc@jqaG>@yv?z?^SIQzok z3kz(}Qy*_PPTAG>yUFh*kG+pNPw##3B7@3pq{xoRw726g#z%8uIlO%-l4B?x^^W%* zi$l5n{9Pt^7pTYG(((Scf#B~KC_3UWvS^m7rteubX6N(nkN#C*FSVF_3rCi#!F5lB z9dOk!9KHmZt0g+%=)f8t6}IW?mZ>b##*KH`2I(O?@1_vv|GO(@`zA!)hXEAWDlm-= zo@m^(JzRh5>0SoNuI_tsABlom6HVUUgNfw&A#?)-P(d=(LLzutE}4lY?m*eDwK%Se zHhAU@=a7`PdqN^_(Hy13{m!A(f!&395~?;+A>w-9kx!a=4@Zxn)@ur!?7aw}gwHvN z@D=A?g2uk5mR%_a(>wHzxH8w}cjC`qz`ave}q!^kl2V2QmCeRvL=_yIV;&Q=fDsNehz(svw3 zxIclP&W zP-WKFZ5awnR@}alN?+2t)grnzz$AP_4G_vN^g6f6uX9_+vZBjSW|8qu9_M%`93^FJ zsC8DPJ0@LMh8#h2w={l>#@6viFv~@>ZX1ern01JENx4txqm&ax+wTR56AS*mZeGl{+&2LhNuJ(Q zo_ao&W4qfL+>r6t${&gx(w!BoOgvbi#Qlnejl{baS}C4gG@SGHxo1VHBF+5>fCZ#u z*|mjmNtudkb~%tmkHF_QwHN|E$71iL$!ZJ!;$um;*Z2bR5&%E*w(tC9ouozXnqE`q zHgO(95pT`#Bv}7z5rY^ilk}M+zUkFrju%SOMCs`I-LIB5@4P~a^VU3&t$@Uk3q~2U z^b|F8Y&iWD3z^Z`9UO4tyE52uS9Y)M*v~#E?Gk!HwmUkXS?+Q};uYI{#=3fcYBY+s zzuom!c(SaX91&nN3SZ?JK0v$-=)-tlfV?;|!MDOq8zIy?(tF5E=PP)+EJiOA}vH1^XK_1Ht%i24a3|UOPb{e`2 zv|nYjkiMy7Yc8xCN61URKEms=aDkzvqGG5&A|A`gl4TA_Y5#J{$Tn#HGFS!j0?9pgXSA;m=W-E6 z4%PgIPiD*?zS3VRP?rKMlNCFop%!AP9LcwGVn1KD($ql3`sDg9ERPAVI2^^TAKB1t z!;%(U-gN?XPy_-b8lfS&d3Q*>n`W&}m0j)bV}(j1_w{G@Y2jd*{im{bpSV}ui5+RO zYR4M)VA+ABU))#R+qDtDz6tE_0|G z1Fes#3cO^lTfH-)k&53an{MLJ`zT3@mnGOM z^*+$Z#I7hG*XP&z=J;ZQDx!ICkRGZdb+cI_lTh#2H`)6Kgp&_}#*_G}gzrIZ3tl%+ zlwQ&-D5KX1kJy!%9m6t@kvA6o?)pe!?x%R%>rQ{3@?JE**|>r%%u^Sr8FX8m=u%zNT=Z}h!4y!kGz+$}Qk zh1Be|GzC68GREk)-FVHX-}sY1=SIRM%Y!_YW;=$PSk78BIP&f>(xrq3$t_3!+0eAd zB-ixg#L>eM%Q|2q9;CTbdOw8!(7TN??u`#lYf<2Oad~gy$~JExx%Z)}*}ERoQO)eW zK}bhbICC~ceCcbQ0IpKP?8X|J&``w-EhTjfRSRFPG~O~l&5T>?QgQE8+OYMu_LEMz ziV8!`CDkh=-8o`1t!KuiY+nvsQ{1;Qms6fzv2sL6p|z!j)jPY%y*q0)9n7`7H6US$ zgAZRT%#0g1AVmU*XgXtMJk&ewbc=dQVRYH!>ErAt1G>JWkf)XeJG1w#)&ewlmY#DTWA z8+SCY%hKQ-YSU{AWm7QINf(TOWS&KW*ZXgY2aRfp=OPY{Ueqjm4Pr>}W=|oT<_UU& zANxD^g?kt6ZFvkXb}75gTb=KI>{i^~`{&q8?^{|QP30X zdQng`1LYaXUu9(a48_e_vuE-knUvJXT|Bynz~qamW$prFxTFi@qo@BX1+*CVL!z41 z!o}0k??CK3?~De42liS%T^v=xP`A?@lXMcqOIm~Ju1S@h z_M^zgmrw8Y;e64K%|$8{_e+SJs!g2J-UsT2v7M*oE!j`*W7DgJjQ{+Fh%dPOW-zy~ z+i50_A|dxP2}S+_;6Et%*dupFFPNNf&X;_ix#&7uzQ(tHZi8b9esOESQMTy+1Y0QS9#O7wN@c!H;Pq=~J#r znN~!iu$d2Uv@(pAv$6bgl*FTf-`>zWULsiTea3rm6L{MQ9TVh1<>v)eaAeo(RnM!n zH^`UKF2Mo>t= zUrP(MzYN&S8CY|$BBL8v*iHtx$D2v-V^#?r;|x2&jaIfWCD5R>-D$`l`eVEG-}S<8 z$JIGB{f9@2lplY)Wh1|snmeaE{sEW>6t>hlvkfi&HX5|J4;7HIT7r7@ZsxGe z;o&9ybv+SI%s4M`j0lckM{xJG0DP46(e(Bn$nd7RW7t*h>v^x&%crsV?IpheK1@EUWioBIIbR5wxt3LfrWw9ci%LdwFhBaCH(2__P7q zBe-}Rc4F`F;UU(Nr`P$X4l6vQWI==odzfX{huy72G-zQn@=UX;8SiOVU>((*lpgCsl)tShiOcCCt6+}0$iKZWi^ncLO zd$l|69$1d&4*|b0b6%Sk8@UuZIiZD1?`7|-Kf)@zDT$M)gGp;zAnKa5=NF*(h{wX@DAI_| z8oY=&FkYwe-Xu7>q-W{?A&*&+D7%zI^wH$`H-U#2E-T6aHY(8TJEj((!#n8+bBS3CnQq z^wGZifli)Z&CFHXUuU;o+sSWpkcxpfa4_60qAK&Y9(P$GcaH7vHqnM%N(v%*XJ#9g z$oEAwY2o?89LZ|Fy-x}=i=~N?_l5a4-iDgq6u13B3tqoOt6P%3a^;5cBch-HXT1z1 zIa+>g`K`F=?LAga{(64Fw%(UInLLNrq@e_4G#5!l=SV8n;p4~KTA(noAwIFcJb9rbPe@wgrqKcfj($1Cg3UUFadv3(+S zRtcDVA>bwvp9BH@U#(TU={vSgQvQkxO^YX~7s-m$F%_zF<3uvW6Y1&$Ta+&oi-oh4 z+Q@(V=wLam(ZM|y*H%fHU2hyyMbdk z;C3_Waz1*g&O%ZOk0jgdOQFGTew_s-)jwf>za zyC-h7&8@T55vyP&#vg7Vt*!#c?p0K@d_Yc&DqFE`Nn%dew_m&vOA8fQZi@=~+I zFJ#tq?ZV?)sF{vgdkL2o&MlxCes2jNSqmp6(=V{i91xe2<4S;2L$nA-5bXgE7yi-E zzs*wb7S+$Pnm36JCKlUPxB>`~O_KEvY^62UUJwGhNo>mT`Pnd)yfS;IfbQO>m!imR zM@=k%DQ-k~lHEsEYPw46!bem?GT`#G+Hu!szYvehMg9KX)TG@`+9A>rLQ=5Pu+v7< zLt9-}pTgg0wCsrnpa)BW^_@e#%M}A6Jr}L)2a*`M)O&E@gN8a#hh3x*LFi>oiEk8y zG9>CzAQW~G+rc;M9fVa-((MPpo$#Ta<(1+2iH}5qe?EI11wB1YB*O)=_`*@kKvUlf z=Wy>0Pab4DGv}u=fAUE-rkQ4fqQpZpoA`_BD>oawovF|=eLvA zE2#ig@Ktf+`W(>)BP=&JL-~u1`!3$R@W)4{7tZ%^dmjaS>M-~r&39WL%@9iHg~9b% zWN^Zwxte)%M+PHHA7$y5M|$E@aQa5kTh)szSr0lTVO6UcG{sR+#Y=(Vw9OJ64FzX4 z`O?ENq6;r?w{Ou*iR=@qLQm-0imw&cq*s<}=i5QWn3wgA;ts2CD01*6^K92q zms0D&gg1rXli0RzulJ)ZZ?`W1-CL+ERb~p5EiJM?&8y>CHB$ z_hU2f#1#**(4crtDZEuEn}#eB^Z<2yO|=^xvK0Q#5V?{DT9gB`=^U;DNjTlU10MCGHh8jXY9 z`hT?&RiowRHAHto23Fz!=#;lm3A#$Ay&;F6HH@84b?6;|Z+N-o^DPZ5z6 z<|ZHo>GFMhY#%+e?z=?YS-NyLIrw*thuRg2~ogcADdUG=dT6cIQn?VzkZo6zLd*;YgZ`;j-F; zxQ?db?*c?c{*bKEt&b;tTJLwTP12G_6U1+nht7Mv*Y0s=HEC=eVcvl*kNd6sqo*DY zUMdsEE^Ep;Ybv4cJlPG1#swb`Rcw#_?H`~o5c<-!>x+`9)r6e7mti1a94;OoQanom zEgkRaULmSiX85s-mPkMwNc5e&~op^%6IF1K&Qeh&o6y=*>S%NJgLd12u-wD5BC<;lAi zn&>Cy?EDy?Q6)QIH31uX*cT%TCUI%@l7tcvcHF+1wQbrQSGUi;WucI2$M&trJ3xOT zx_omSRSC9jLre2tTVdO`hxPZDL31x+S;&}IE~)>IBaDxlBn^1>o}hBy8rxpIZ?lvX zcklOZdT%A;g&jdKKV3^DFhj|=3!J%qYqE1q-||+PH(ar*-iHNps&QDzQ>cSt29r%D zhh)E{xAQ6@=GpDlrOPSj2}Uu$>b#Wfe2%2Jk=fMBjIw|`!=p%|fMO!W1HK3cHvwk1 zOC2L@Luzv-`|mUl(EIYPK@&URGOgWr_rAztuAhm1G4>6h=6-6l7>%$B?eE;}&qKR+T5LqV0 zG4U`*RKE|S?4@T}gWImL%@y=cS1$y`5f>T$l;iJ|E`FN={1qHWgKOugcWL4l&x}|E zZSK3SqJjW_cydXKd$W!PrsJLBht}P!e2*Zr2yrel_pS z;LRzCfgWU4#you|jUMHyh~kxmz;e;eeFQ$PU!o1=acbR6o0N^<%|i?P0APQ;Nwh7Q z!(&NiP!^}TU`geEFo29aO4-i6Te$~4%Nt&39lx!+wTXd$!h$Nsy^l?fCl8$m+va;b zdQd{-!^e~3VIp*usN1`DTZ-7Nn(wui9ZMU9MjUUXM+Gzot9Ir_2k{W^CjvQ%F(fy! z4p??j%nSY73y<^k4X};7Ctcm$N}bis0jn-6PY-S7&0ht#qeW&j$IMc;aCPkL2ce!i zkz92mV*|IUD`Z;lbKd#=l?DLQyUlX;j;<0k-1olfJ+mx)w*-BReS>cb4wJ39?3&}g zUkz)AlJBJ@8SV5vB^`q}+*uXY(XzO)-cy5R>8o+ht6M*NpNsqcu29!3e{9&(yRv)X zLnUuZae6fDJiC2X(`&^5eXs=4#`2SfX4>{M9SylS^@%)AKh5pi0 zrJR-NK|m2@PhR381r|On=W|v7Y8&*CwArqyG;NplmekK*pxwg;PzFer_GlWiIerQ+ z8?kU3Ifv@L5s5KXT63uFu8pqloThbM#&FDxr)`bOf=;UKH(+5kmkv zO2$eF8LHht_z4sx6KK9jHjJnOan(W`Aabf_5+bt6F*R=Z%I1eIg_Zt;9nV2_od;wj zkEi$VwI#pQ_+{s3$F&KxJh1HUhHIjbO9D!5q#q@^0|-rCV?GQ!##%f7 zM|)%I$%B|4O)&OsFj^9y(zkhc#3)8RiBW2YQaot)sfy|6J;u%Ek%a~uH-?7ECFV6M zz6n<=dA5Symp-PxI6}~Y0%+OGn#VIBM>;V1a%W^gE-8CYf>-F)^V=#NPe{pQX?&S> z^qvB`-q`y)lF#Oj*l3}8A7ebIZ*kBkK;KxZws?eM-8m*}h{zB4eYA*bnzA{ArAhEg zOe?Jvqjq~ymvisO2=vyl+N8jQ_)>oR{Rh1d{P-7bir68W*|Dtj0@NQT9Y)GO#;Z9; z4(_hKN1Dg@tG#2nN8xY6`!0$-UOrn_VP9U(luORrcq8)ir|f#cD!ns`$GF)%vqHr@)H%hnP}>6;JgqGoM&Ngt$6WVyBbRKWD}9u~yO zqkmq?o)BVM2-GT`jn@Hu09|F4XZ1S(&2ep<{E@T)kPc>F{<(S`c+LTJZs3lzP7f&0+eQTWK_X=nU&-Mv8l znLP=8AtNp45IfMNclcl-ZN4G<14x+RL4!d!lZGX4x@01H<^L?>4%{0YyLXX&jwt< z?x<=|Tsi1g+Dn_GN z+b+*!_r2^r*m4KSy|acRQmVEd6j!j#FgMHn!sm;Cip)yn!xI*J2h7AVZ_+I`R|zkS zNyi;dlEj$@gWk_}JKTyMIkN);{aO7FPo=_ewY8yeY^dJQ>rw@3jrrBxFr zp16?-$4yuSs?$@SSK)AXC~w+*FRN;c-P6}8PX-4=RJgYr2czLATw z)71SRqPcdyz2nw%21Rb0HF-n)Ifl`QMNhn7mxqd-}P)9mp?hwvZV&x`V8 z7`W#KCv%wb9WuG|#EVDT@j)P5)+~Y)qv(of(?3j{k(YyAAnRe?IkGA>RLoxcu-#og zKilw@2VZSD&fG~R$R}R*siQKvo8;_HvmXu?D*^L*u)WL?V*?74XeV28O^FaM*Op*Shw|eXblA;n$fznDSn0)&bS_^y|33R%1k#*Cq z$3o!1gdsx!p~%<{4Pad_fP*(-M|E`KSWX~>lAP|qPjVlVwVKL)+Cu&^_|U5|@mDuG zIP1ch;MXCTwbMorrsVpv0o2?eZVBt^ukEs;db&CPUD^>+e5u7*!?oj1+x{&`Wtj!z z^K{3)@ag@h!vmBghl%bAslFctpJU#nJ6x_J<319Zh8sS8JM$h*3VqhOC)C#2_I51XDlknO#vXzSfYj;J@qeRwU7UBT>lJOVtu z|7?63ajqSBj$b)uzIL+H^bP~(r1yrFZ$PyZS?U1!IJv~ zVjsnH%|uipVvR$y!!IlcvW^R()>|?JU>8Tku=xWYoVD4v@fq&01OJBDY@Rl8rw$Jh{7rYsZG=NZ9yEr{lyV>9h^a!& zxl>0tC_1{Ist9L#&$yeVIx}&(V5cBz$pL6hR@+$o7S!36Z|vQ0VjHAc^-lQ= z^S-%vmbIx?9<9mm-KNm%;u6N14H-A}9_mQGIt1+qO();s>`B%m-6txWb5e`SF{sS7 zbP3=v^v!3~dyDct-Cr0&6&#EmT(8k#PB6I#!5y5S$<3Q^WB}U7hjEOwaMvtH<4QpODEVnDfs) zdGQBth;88Z#DLyIe}h2Xi;I)Zd+s7}yxcF(r^Yg`W|4TMs_HQpneF2l+=9t#!dfD6F z_HTdN+g|p$-nRI*mwiYf;EuO_$jb^PpX)>Z?bqJ+wzmPU`Z4{O3i1S}|CkCq^FH!D zHoASw_xP5#kkcPFVqR|a>EplFTNb`n^K0!*OHw{LqiV*7M)3OF!+8x)4bs3u>9MVnh&K@Xf!`_T@gG;P*@uAkkI)|%&wC!;5BFhZn$kk9B zIk)}v2?kTQ%Z744*HZltbKthsrMvl%k9VT?Ytx;*e^mDJp&i8`oc~S3aW1iHD8SQ;TKtDNo zCh}7`E*$&TQyxleKj92Y)CyXTc1O;JUKdv|>j9wr@dH%7C!{Ig6MfLvbkYMdnF;K| zMP+jy)P`diA5i3@m4}9w>b9*1iRJjCF{a9wUslFZ#2391kU4qT$m*nVZu_JZgE}%D zGyS2u)B7>J-v#3iqcLLI(|b(yMg&OAIj;wRYRj3H+Lt+lBCzfAMR;|ZF*jL}E;8g1?s5?5i~z~>8m?Z%QWBD} zx^&W1K!x15a^Ie{ai&xVn4`YwMlPeaKNU?RjKf|LN@LQuaxjEHu#mQ)mH#uREH2iy zHtoswl_Gbiau{To7f=?m^r2z^G(Q zLO0!b&E*eW3JRHSz|X~5TgX?XNlw#Cj|x_ELS#Dhfu6qg-Je4?DrD3kGCOkcY>1J| z=BK7EsN0sG>isjE*fwo79J}Q(%=tcgBj;f-L^3@Ua zOK3W27+o#&wy74C&G|xo3Kzj0b*`01L%+VV*?JAHy=QnWR2{wb{ct{d70{eqcazg_ zb!6S@=mK+$nKpZZ$_&VZxlRVj>d4dkW~$%#c8xiz6@aXY*X<{>#(X_P@wp_>-P@fd z_ieuSiI7&hMfTz2?}pAzd`-OadKktDs)t!|*@;$kH;z4|H^QZ-hWjlPvV}iOY$?GQ zGecdIruw#wo(NiC+_1{lpjq+_Y?ey)0Q#Dz>B&<@<|E$U=Ptf>thk@PI5>B>PcCsf zm^S)B2Fkj-q1(78d3Be5C_W@q$L{97_V1OSmiu?k0JPyJbW1MXRogmt+#a(YW@%; zfqXMG;4RFt<<7l>D+M6X1OyOP^WN!$rTZp=_i(weg~=+x)TBsnC1HS(vAr zt?IgmAPW2w3K_B73K54Za9@Kr6{OyE;jDE4g5OH8QE%*q(#O8T+Ul&F+=E;ip1yu| z8qW1CW>jxX>hc7upUZ&x%U}5`pX6UT6Y$*CuY7#<{8gvmBUhixl(;YbWkknw83Fyv zu4eOPpMCDb44G$K^QuFe4Y+ymFE@nb#Xt9?A*8`bfADur8Up{?Mq2}SlBKP~%~W}s_{H}JbUY9c=K1#G`419W^WkT1fAHyN76TDa z-wwdoGsgkFeL4WRuLZQ{gCD&8+KY=JYJY9@>DP{5yB!d;cZb(L7zjOHJpZxJ&mYVE zUn_W`Krwer7oY$3w=KT57|~zm=X%?}{oV88ykc&~bOF{2IWPM%KjdwTzjgQdBSLuf zAwQ_NkgKcw=ToC6Fzek~w zhAIAfnm6Z?O{#y{?2_bhGhZ)7zY-d&q<(T9-%gm5RP^4PKB1rk2neK<)0X2V(^Xj~ zBgoHa<3m+dKVA&L&uLsVEa=@=CWBf{l(<`NtT>6^-w3mzgO^w#&{Tg&P6UlsV_2TZ zrIx20y(Z2_5d~{Ki*tu@XZXqtAq_OjXP!>&USupB&u59Jnwdszfd{Y_=2qoY>l4y{ zD+griU5a?=|L+FT&94+g-tj2GDUdDYFN2MvG*OE3-n>!;AkYy4J^ibB@0GT0tdi|D zT;gSwV75t_61LlHDs-{9Lpr?CJG?s7Gm~P4ZA$awYA6!yQvP!De5&BsyZhwl7L(!% z1_Ta550Dn#23qXQ2n}h(<8c!7eSUU7fd)+`3$+kl{-%;Xcwjd1!qo;Z9X$0Yk>;4-I_PwT#7x< zVA*yx+6AAb6L84Pnr%LPppd0SgxiU>$MRfwcP-K{>(SK;G$F~Wblf0;kp|f%85M`| z65+>CXs*@4O&#qvcC~ObHa{?A_aQ!Zv}^~CocW~hj$+h`9c7|Efgb_HqoPT*ZCh*$ zg7pPFI&gKWqsLBi9p$VT_}s=q-nWH$H79s$i+fQ?hDZGaE|4;kY4Lea_}g8@ZOs6XBx@nc=!15 z2y=Gg>i67Go|A&3ww1BkvE6|@$oiQ35wlV97zw*J+L0HhpmN*VEB9{WJbJU2HI*Rp z*3Vh7_&*%NRukW=%W7O2#o2$0IhvzmPbMBRYrRQ^Q-;O!hUe=Wowq@N#k@@)E|08> zjP3{IiC&g18QQ995iVNlY`)VPs!7kX-iGqwo>8*fyN2O!63KHQoq>$pv4K|~_lmm| zp19ArOO-kIi96R!amPPffSa)GiJD_@uJ1+WJu7gPz?2w|@gFI)P$6)!* z$?sss5#(5xw%2wDs`62kdjOk&f3o}994co3&<<;Q@9j3?U|f7CK7X4Ezji;&FPTeg zVWt=Ji`e4kPIpOSz3y}?BD#NU-TEw zGW43&&As^Y7bUf* zcRWTc@7KhVbc6{`V@mc3G0O-hRfDrt$x7l&0Uj@q=PA<2T@VttsnuH}#+NOXCGDV? z@C7!2)VXQqS2074rx%G+IN;@rtM6ZZ=EEfV#rbF6A1q+?nSiRFf9Ccx0i%8Ym1nL5 z+$IR|{Myrjj`s&1W5P48JhK=mdgiq&q0cxFwDA7dt}H(D^rsQe&nL_MFL`2Ptr))_ z^4iy~{nlT*2w?oj)!@Vev`_Z#CGS>Ecso;eCV_3D{;*Oh8~ zFRN!N5_892CwA6M%tb3oQ8>iS@=9Y}5<_ClToE+*I>2uets7Jq>-ZZ7HNAw2|Z!<1g4X0c#ej~9K1&PZ9~sk4~6kD-C*q3GX zUhH}>OuG18gd?7=E!U>#W*b9!KvXb@BWDe_4^ZF%P`wuydRHr&{stmBn82M5uZMz~ zaq~cGBgnGq&SIQ9Q}H^A;@o!N#_xAp8zWy>WMFg2^SrN6TRXG zr%@ok0Vzw4(&+G4@#VXt2KM=ez`d)!b9o#*vb>$1t_SjY)-YMkbEIjW4}A7?B;&ZO*%Ua;f=D&QrU0dW+H92%Gw- zWiw#W;~O|=@5Y&un{#d4J$Rv1_+apf)~tMDbqP83GN{n8R6)n3%)X;l>BiGz7Q6t#4^V^A^=G|)o#}q(t9wIK(0yh{^fTma2 zwMWg*i9eFoo2x2V&hSS|Zzkgq4P$a_k~& zT5*bKdTUpBNo$CD@!0*t^;&gXj0YiqAH1`3-1=gTTrzdMLdHTAEAwk`sqjtCcb#WO z;ZMu?O(dD=GTxTYc!5}@)9uPnphC5W*uLC{LRY`*%`Y%3W}9RD{bA6EI_YS!CEjKH zW58TGKd*j_o&^ixkT$-zQ@s2e3tdegOMZx>E>HaQzW8kWOz&~*W3KI@TzaDxD6Jj=w?v$w1VkdjxsdUeek^ARE=xhMxYfxVP3}Oqe zz1zj28X<6C){-`>BWS)H#>R|5LYKvJkg&V{$PDGsV|{Pv%JHRn`aWAp%sN@^X`c+( z8*6u5w;+UPA)B>2?yYk-x^M1w7C%9LaL48=?kA^dGx z#4Qdl&?li&<{aC@($9|s$~Ns#;1RQt1AW1id6CtqSi$Zhun1sRS5Eb9mi4adFw-&MWzhg5`k^+gp>oX+$2QSVq&Ak0D zL_Qgx3tHW?!0oJ6X1NqKS4)Gsx{^Qal&E(ySymybcp9>oRewQAiv4N;QN1*8`b5S% z(4E$EF8X-KOW~lW=6Gfgp(yGKdvdL3GQv!P6+kNpay?M8zYIIOF(h<g6;gxI zeYVF)0&s})b0xtYhk^ch*xhvGkzEZ0owcK+!h4g-O(%(`c zu<^RP4M>DqASY>%(7R@{y*~G1 z2s`HT)C>z?k6cSrPa_S?oiE_*>ABOE6xWRQP}^R*+FCy+NB!Dlf@$_K!qdilo&>io z`%xf0edZtjkC$dMCFJ)Xww3snR_uKV59?$n)_|xuhcC)x0Z{TpcxfjT`-#OfR22n;@NM3e`SU$5uoUy9lCOH)r>JNRdpImr!36A=RDo-Ep6do<&_M89fLCvoE`h&Lnp&nQc5i z$w3pYCWUPYf^(^qJq8`KL!7T)iq_3Q>>_$!sQOURtig4Ei)Qo~00T@^(?svfZ~T}X zyKj2X5INVW4s|&14#M3gTqROQOUuWUE5u3O-t$pTQK3jC4Jdhk2#Ms)@6@ZPp&xUYmOidqo2yrRLi;6i%?Gzg7;AFMe8T|i}j>-vI{wS z2b`Ntxwt4C*;`a7dpZx1i;0XSA;$CA{*Hj~9iUuRBRSwMBuJESuGjMWF*8RZ-($`{ zcm+v?FK>ypw$+hG0j;ybhI#^ovf|w>dg#1-Pi%(8DJaakalE~RYJB57e62azs+?GS zD&39&dT*nqN+8(^SLvMrX96FT%DKAR3Iwd!hH<$u?uc*Lb^k3WHhot_ z$lXF(+>cU~K|?CCkX={m1^uEi3kB|S!Cm=rt8N{HQr&(RS{*XJBI+b2*Z~)shAR21ulFe@pJPD6z+My%1OX8=;g?XrvMZ#m^bo=yutloHPDFQkyD))^3T zEZZ3#<35u=^xOA~i61KR6zyo&pW#LV%$~1aOfvV*!E(Mc=)S&yWCr@7l-l4WKutB& z`|$9&FK!HY{vp_UT>Z6sa_@Hy_G6#jm@PSu`PPw{;ay;RI(yQ$_NjY`XTl7jI|4VF zN{J~)m}p5lR6}5xJli@HPJ~3E2aUXG;AoXZhSPBkI9yaAJNT6S*FCV)_Zp$X6n4bN zXvpZGd=oCAeQDI}WG|gP#U5Qbjj27bHv~R8-Hws8B63;~Y}NpG%mVTmxL=p~yIRYm z#-Ou|U?1hd=3A3GYa+)mA!Zjk>v(lgB-qQfat-U+~cso{a+kA)s&N>t{NE#7a=i5(ccU2tx&I`K}F;F5?QvH@KDWte(ft_&2~dKhr^ES0@IB3;UxBsYRZrA zwvHS&4Y6>NV;3W2fXt_m$(h3y0s7r>Syni;jqhW4E7yr zdpj)pZmI0a!ZYX~9U~<14wH7^l zjIVJE{01@ETi0RTHO55O~;S7S?@XQ z^tRev-g8(gl5unE z;a-aFLMQWSy8lVwsb`=41@6CP(C6V!49&Ma-!Yc&E#n)^_p$eWkgW;znvx-8M?Ts1 zf)gI!3oqopXUv@x*EDLBzS&`~G`2(Yzu9J+(8T!SQ;}`W=d03}JP*HaA+l z?A?0CLeSkwX8oezlym}7{Tb+N2=$DDM!u(Tbm&%R<`^G|7ZvXlsytbU+ z`S;n}#EOGg_4C9=;il{O*T*O_jR1C0()q&K>(y7g{;q59*mY$5yO7P};9e8Oe-q5< zpb}9#oP9({}Bha}pJWU+s-BF7f@O ze)nBGIU;HXviy3Lm`d8+mb|GL+O5#{gsK&-o;+8S%^J?3k%%4{Di4L$t}T$ADZ=`$ ztdSY|FV$7y<+U#ci`a@YMCcd)ds>5fLB3nzkkrP#|B`z$aUTuG{sZT{J32*HVR1(c z!q^~a<9PJjGj}u$-0{4SAX3@rD|NTI|9b<3XO!vV8jjIsz;FsoCCRTcB%IAhUi@QmX`+j-bS{ zsq;dOq`6SwW8KMPBMC?__MZU<&xm=bw>)Z8PVIr|Sw=AM`;5vUqO~S+47?I;MB*Aj zhP{-*MG04Q4TKCJM{EwU-4tCI&tjDW=uBCacS`DIj5WCcWMFTp8+4xf_b~ zGxUjQ{uyZbh4QjDt*0DR>&UFN1&uXzA>(_URUW8V_OB^!6O;aJT^5>Lp()nFQH12J zwc|DNXEl{Tr7hQdgbK`fM^4G{%mbQg1cSQbWL(eO+EMa#=W`=*zhYpby&pIlMw94% zI$x}h$Jm?1TR5~&*s?VqXE$+)`9F>?!QiDr1>s^FIci7!(EF3nrcQqB9W99c3)zj{ zO=IelOq>+g`hTUe(i<_4Iak7O&j4~#Y`mCnHo<#p`$2Y#2G06Z5PZL(fKkGg9mbP& zE^2+@@gG>@r|UtsqfFU$BzJTC0;}G`8Jj2@N5|#+VQ>i9W~xJ=W^xR36C=%*k@OC zqT}>Z5QBjwk{nRTG|fHqDKi^d7LW&WPaHdGCUv)UIvl-6Qc><6K?GaQ5p^nRb;O39 zhFn@(ENGrfvsLCnK$g=Fyuc`pt;49Pb{+J!lymn^x=`hsZI1ioTZ}eeprm8R6n69u zzD>;?&FvW3#utg|_@tIkNzB@An0f_P*EH={Ebe_$K#C&|zNw(0wLXLB;5DkfUp%yC9WawaA@3r)?fnF0$QDh%JpK^;|GLRWxKqhc`dj@9 zAScDftHgdEzKj|g1$qD4X$WZ~k@1F|>*~nvd)tTG{in7qXdmC?{Z(pnx;nJ%O%e+w z7y7r8ps4E5cS*uHYk_;}Zj#OUB6n7xS1k9CPup;x#$4KgEbwv_btTs#%Ze&$U79f} ziPRdO0i~3@()I2`YeFD`IBSNwD_05?k5TM(y6w}_Zdo4Dn91C+p2V*i z_Fm#%f|5CZ;kDP`FmBdsu+n(z6f36UiAKsjifbDA0F3W_UXXU{eOJr!P*YRaT*hCy zk%$RD+iAiu{G=Apd%17PV{z~8bvHWP55r%^C?V>$e|FsHWninJ)%Q}u<{67PDgZoB z{vciJh80gGzJ${`l7Pe?KB4!}1yng;wt6p^eQ0k20me1DkzJuf?~}i8K92Xn83*^1 z={rbg#h5397?XRDV}a?#?RhgudCVlt7Ma|Gkfa8`dzgEJgc&?YXJy)80qS8kQeFW! zr|%%jU*5FU2^>G-@TH#UX`dXs2}s6Tw?FZP1soNrGh~`+Nk}-}{Gv~`~#}9?_QtBnZskoIalsD#` z<&+o3^}A7aLj>AT+4uAgD_BlQFVi0lJbFHCkGQC4LaUoG=2hYsxTIBI+sC6tiF<(3 zE~C%ITA{?{%fT1?`yK_jd!MQW9^XY3K+QN$=28P?TM^agKmnzA+51rMdN1<7`hfb1 zgC<@An>~WHkXEVvB+C&qOkLBM@8u#96QWO2vAknDeheBT?DoxM!2=3#{g1sX5N4c7 zVU!S+BAI@7;ywV`>isx^otF__cFvN|GY?Ep<1JOA)vY;nuG2wsUL57Q3)*En`&Bbo znH<{z25`xFj$BvoiUW_2qPPLW**9v7PhO&Cta=I{RIoC&PR45RIoAbNo^E9DI zA09d|r&Rnw8_$Mq7Zg3t6Ls;)2YPj9nk}*$QD~n5lC~tz;+igB95nGlLm$J~?Fy{p zrgrB65ULtl{#`B-G2v@FO&Es92lE^GJQRSv$-fEk_P$(B z?_-lmKJ`IQE*sFwBgO0A4+RV>SnWMn%ShXmI3im*eYJs>W4GUY;Wty#BDZ&&4!e$> z6IE9kw07>~?M*mdyXt4Bl6%x0gZ864t$2%TD+A7@5=L%f z0-Bvd#y!|o(aSRTUnmM^1*1H_5AM{*$WHETAntO;dVJ(73aUhlQ8U&r*CvJ19_GBn_EEz3M&K@c?uN zQOqs;yR>!=ygI|g(a`oJB8{X!2KRoel0fQ0)CE(k_mDI64x3K2KAo#I#vAtZVT+QX zplP6Hb3RBHnkh(EYww4%^|I+Z2O!OyI59u0ED{GyNBTNoXs zv?uo<_Iw>=L6rMudD#);WTzR+>Kd3Y+lamOfdoEwOBty4Kyhh#Z*jAv7Cy1lc4Q_L z90{f%%~XLzBk|tuvp6-TI@%KIb()us-zm|<0-iF|?w&o+^G7uv@sTJp6dvWsHB`(9 z1O<@66_Jd6jVFK;OVv1^q1J`CLo>DCzjDVlE=y^Be63(ZAo9uft zqZW{86Ax~e5D{~GczM)#0hT9|Is$#a)nnCz8bE^ zX(XeSe8sviac5ro2o&G^H2g%vozuDJR-1X5dMdCt+lv>Q*xPZ!wsv~Bdv&*+OEvAx z>+l(P&ZEs=0ycewJoDfjcAnkImfP-()@fT>$VM5NusF5GGeb0e7|gEla`fp?oPg_@ zip-iPXYCnLd2WHK-wH#Z&DFzA;ieiDBvIar%$xz%f|(rxy{K>Xa&$gM*{Q(sUbefr z4;Au}_l~XLkqR20wl=N@(wI4~4gxoVEnrNJhl^hpIshx=4Vx~zo=l9Ft4=QH0-1Il zn>V5sz*3Y8Vma(Fl8&neGNf5uMKg`LMu0y@fk#&>c4s-y@tmU~p?}RedWTji4bg3{qONHAZNs_CK;^owDf~B^vcUy!$(0c zfNai}K0KPSo~9jEEuT1H=uKIzUxx2&y>YuDnx4ksDtU*HE z_j*sZ@0yvdwZ%PZpjBYSh+w*<18HY5IC|%19Zx2NRR|np=#%SD}fBb9-7mOw_2%cGQpx&mL7s z1ot!u0dDUK-Kmw4q7ow5fFS4f;N4-(rPj4IChWVucgPt}dFM{|O#>|_f8c2$12>Ab z0`K6wLv)%Q!5NSmltCm1v%y|Aegno}Q@Qfa`+%H)8w;b>zIO3CwC*tCF}p3=K?*Bu z(z5oZimYH1PMcfyDWq%K5VFtvJ*oY6ZrU9|5u z*R+5j*VD&z-^l4DjE&WtAL*86qNf$eh zye;NE>YuDR40~xXXOLjD$$iS=hi8*eD0aKsx{`F4z3ZWZqLU3-p2cf4E-Nj`C9(Pc z!>pSns&Jp2%?yVl0QxtSUaw*2mrYDxBPgw$f12Sp2gQ=CX?`|h5UEgA17_;(b=4uG z#RV3@TU&&!j)BxI*-@M43k(O0#V`Td+2p zMW#CLBdvGmq<#IL8(rK7JdCM~DBlzk@kjSQxZCS@XYQK4UT{xVzm-mB5P0q3(WReX zaBo?0HM;%6d^ec1aQHIJ029)cPw=R5=`hsYN#pDv+#LjrEI+nRf3`nSAg{YQxNM8~jq5I?+hXWEifm=u z4p}-RPK>+k9eKE+ih;No3YGmBEpvq?R8RwCNePaj<5(;RUePci z{}^ILHd8~czn|da+0nde>6z~t6X2-r(bsKxnYdoAU#Tulnf>hf#mh&ES7nc?Mz(qv z*G@VXW#4bR&BA2;!7xQJH5pBXT@2eWG#Vfj_^9H+MVDPsD48cuLB5528nzDCv``{B ziWQ*Co?XG+yTrVPrnhV;x#^RE@}TU2(Y{%f@a>H4AJ}(meVY3xychD_j$Plo0&C}| z3PM9K)V7v-hn7zHp22S590@{Oj2*Is!%B|NQH zEJ!irB;kB>_D(4Badi5F#zwpA^2Jh^^9xVi32+j{whQvrczYZt&Gtj>DIt;EhJEcF z@@er^GI}??_NBoBoo0fs{+%JfkB8l0r4^X-3UGm zaOCs#*`uP&0A^&3n-~p4?xpMLA~cy!fu*i*P>6`U>4TzINYN>oEC19}Pu;(NaQ|SJ zuw#>VJLg(58{*W|3x>bLod7v^>Tl${UGJ7W7YkN2p`{MFx3|FggxXThSi-ASj3y1Lf1Cxu40#--QFG-H6x#HRjd{8kbqY2SnjR8D+}MO%fJj= z|G>UWNSkHbtRIE4kB1D_0_<2zqA$r8PwAAiV_g-0Ugj-&>a@Yk%)1a%5Qb>4R zyjF@XEs+KrMYBXrSh9hZQEU@ObLH$jD0h-^34p6zdi1%38w~JfYO1irV`W@cwC65? zT=FVz*5;{=d&E8L|C9UFeRNNEbFa9saOX|8AKb@oGoHCG!nGpH$cHzOL{P5NUlg~r zJsR&sbBJjm0+7~X*|jofC5>?_^KF*dz2dJG`CiU>TY=w2?kPYhGVuJAl3K~=$SvP_ za)aufL<8jX1yJKl8C-a_+&*6sU-jdbAE9?urg-7GpH7b)3|`0b@Y#I@-I5NyyA2v_ z_RiORL}+VpZ=lUM=lflE#WlVCri@kqw0O4?hBu%zZFFMuu}hVWZ;TOo9|Qlp{C=P8 zqP8`C2U+HqjqT;ZDK?ti<-T)6Zy0dq%dOzY&#bqX7aX_0>Mi3UmsYdZZ%`R- zd%knISv}jA)_kF#G4CI4o-v*mz~MUO7iRFI{$koembY+@6peCbjTqo@7wABb&@HF~G%)zsl=ewi(jPPy*x} zAj7w27iDc!FKboa9FkgZ8u-D`EnurXIk-1rcf) zkS?);;mbEBEkLY=o!)xJssis#A9Q)tSki%YXHDt7z6xp})#|M=JhnJzgqyu)oQ0LQ zHum+VSHmdR4z6scSN)<%|}W}BW|pguS9`K3bA z@~cTR@7BZL@n|}_HF^iynx{4$@%i$e8Fjl}8n*PqEKFo~c3NB_ufM!=q2bmnqo(DZ za(g(R%c>XiHa30b`g}(#kC<Zxr%rX=9cxzva_Ws|;v=yJyZij4 zT+h_K88=TFO^i~) z(RGa|;L=u;DJqK-VtG_XBN~ z+0{GRq3^5)L0N&s9|W>|_izyUYgy*SdnB?WXZp`1TOG6a;eqP*7m&nP9k+YG#INvb+{{H^e^)+j9L>OCV=Ia5AG`i+-lj2!Zr(Kz=&C0K{*=H`OkM#_-YcTwEZ z)<=kU2z3^&_U*+n5{%k@`+7Q+H4MGhmn`m1_#nbnTz_KBwRiKX$EL|U*^-X@vkwK-bEUI zLQSQM$L0l}O&B0Eq8`9!q73#Tv&V89=-~wJ5%InqM4N8ryp!nW1mT&6is;sU+l3hc z;S7|Bu>S*5C2M0imo6F zvMOsb-WYGsp^@n>K$#uiQ}L38r%IjI{Y(aUF1Qg_!yUk6{?Q$2gu%K`-CHA%0tNNIoWa^j$OzFnvi@N04Yly|(LNJH-hMLTNf zbK0=Kd{d%~90<~^xWxR?T&vEJ0e2sC+E2mLi2u_2vV_s+Na}sc!3PP?i(^o7mEM7* zJpdf8#AyqYDyr?gkN3yH{9+;h5UNUQ#bkE%sU?&&=(^cSTlZ}1ATDArFMX&SZkkf$!n$eBRG z*~8B?*Q#>{1D?jf7kkIyA-x|#!iRdFUg_XV!ka;F9;uc)?viBFe^_$kw8GiZg2nwf ztR6cIWP>AEMgeLIlLVRFzNq(y0Z$=jCjq@XeEoxl>HblYNfxC${zhkQ6VL|<4?|B) zkI8AH$%HE-^(#uDU$=B_&Ye8c>SVJA-^Mw}ww-Vw14^*hjKLVX(8Jw!xme}g!QEV* zFH+KGkS_3-!M}5-vrd{6QH+tYD7#ODe*v=w{V5SXB>7Hhw!Lcon0s*J$h|}E$CnGx zQ*3g>hZj`i8Ydz*b-P_WX`oym3JY5q*ro`~qVdNFY~6d((83x6ydKjK(zp@r(imnG zwg=pSKH=ujizeO<-KL8mr-*{Q84*w8VSG9$O}#sy>9Zhq3AoKHmil>@5v=0j?zU z+OR`uGb8KDLGShL5aNLk3(bk=yrD<~azXJ$)H>H1!LCm!G6Mub&5BFR(?ox&bIX9c z4?68p@HFDT^nOqRPfS$RdoyR~yg6`#%4P3y$ChLjNjq3j$BHi<9R>S_*o=gT`yQO1 zsNNpRh*9Wx3o|qo&C>*y`4R4o+18ue`#5J-*4S*GNvLkLf2!m0-5TI4gh$UMN-+7u z#O&eX@wn8qZ*>UW&E{d#kqaOvg8!1kT4MwE>FJjQa=jvpoq((n^d-MvX_k84%L-w` z2TRng!3Yu$-v#y6#<>inQ)@iDuyKT}+<3Jy4zWLc(Ola0B^VC})OQtzAF$Ufy<#QG z8kK94_i>2xh8J?>b#m_?xdR(C&+cYtR!aoLxXYnCC|@SoZ|;4Zw@%!dp4{`<9yt30 z2cN*tV`XT~&AodmC^Wdv;C6vk!v>w*M`I7?4)Vfq^_FrLGiTL`dr>AT?2rMZ&gJJQ ziEr6rQrXPtHydgAjdh7s>uz3#d50iJR&Lx`}^IW=`ijS9Q z;~(j15`9X+9US~QYf`7fOAQ{^(FDJ-on=u5r7(zz(aUxCXWT z?N`!W`m+#ic&Qwsijp@(J`pvqd|Zz+gP2g@+y8K&f!I-DRkVWKYN$vXdQQ%PNNb+u zZr`OAaZP3$WkF2$ftA#gb_0?pfv^qRoFqK_q)bfE_gGyABMTD~Y|n{Pnx&>)6hfFA z;Ztxe;fM{4N158@5lav*(w=)+t^pnVwWY`QH8&KNYr}Kc{`wcb;&yssz6101OAO(D z$D!ks^Owb@a;?L`@Ru#TnC4@g>lEGW{Cu@s>)$Zc9iCY_!_Ly{&OCSe&aRG6=1v_S zYq7)b-MKaHx-!Eq&rd@uA@gw67^7P}ghaG`OkKn%b65PC>qQ2jdqXiV9ys;JGy4uD zC**o2GGd;ZnT76(<^MDFcg=VPb4CEFZ5K`LcKJ4cH@MALK)gvX>JF7;wi1P+jD2uF zAnX*%%k4t37cT7g0kg-yNq9?6r#h#-e@H{w-VVBCH%F)!;_tPC6jIhxG5lbW=za3g zxHolu98?DP+R_qd7~e{K6_t+tK!*?TQpxE3Q|Q8d__K6sggKYq-e+GwFWW^_FxaOe zZ)FJnIOy~quU;gf_mGl68%L?=)H{Xpqz8xJ=1Txf-o@Y)EL*)t$3ERVoHT{H6GCSr z-J-GQJqFhAIG^RT`=ZikvdUPlI9YrlWO2O+#NO$U?TKZs<=&%>QRl6}({JNh^vNI82BZJ!R(5%nO#r{sZP!%yvet<6!D zqeEdI#_Ff0?ZY^^J5Z-;KhdCuk4o)*F!>vCVg~u?O zbK18SEv+4wfG5qG|Met?7GID7?uteugU)o%xO$Kzxeo_Mpcx+zge0I~=~T^><@^{% zoUed*Ag~H9dm#7BvBSut>?F5E z!oDj7XQE}U;oh0iCmU(_lXa0)Pi)EWPy)`CT~YHRa@!1T+z4=x5K$GJVtixlxvt7b z1G0B#qKy{{=bX{~QgDZZ_a8q2jW+&I?*iSEQ^VKZsVnCDl}v8`1jN(SBIPY%ymDW; zjc!9~ZxWC6UUW7OE&JMg{Pr8xUeLZQKp{=uXBA<@OMRzK4y zI?vtRm2cbehUGIm90~8DG6nAqm!DWa@bqT&Geumd!1uuBDvdT!;YBq$GUNKr+hmVoVmQnJy3jwV#l#j3XpN#DM4BR$Fl6N)hPQ23+;#RJgX@; zjf&re-LH)j%=pc_F&KHuB7Yd)#&ws**7KCOEPR3qL7phz;M<)W!Fg00ovgO@?45n^ zZL0SGJ%`suVINfX*7XC|`Eg(G4~?{CZ_CKd7q7see!#16WOZrU>DRmUBBlGL66_c* zzFEsr_lHU}FZJ0Mje$;lO{ec5HLUsn^+fykz5;BJnV}+3eGd%QBsJMZiz+3VhXv#c zVuI9YOBeg8_iDK|g3FuyZV{&KUd{!#N+?M1Zxp}OhmlEyJ1wJ=G(u2TrKUdm@>Cdt z;!X)^wKwM4FJ4k|WQciF5BggWyZ8SL+mT?#eq?-V4~*tqlkdX%Li$dHR_9vf*w|)d z;1cw|;$yPTg`}-*d8z0cZ^U!y!6&C7xcvGZE?GRama_1-?J%kPJPfW1b80{S2vLXoXxei2!F zt8UeIH^ooQ>Z&+A)=bQpN!#%h8_#IS3Avt$h&sVpBuX>r%|z_!&21bTb4@EvuGf^Ghy{%UB7?kSr>LV_^;5f9=k1#M+S7! zFsg(3>_WsfeH&Y^DSw|R^S~_CUKwpM&CNk)8h#1;LGV`Z16dhmsjMA^u+_rR?FuXI zh(VD<-wFXikb9_iU06Q6#CgS95aH~7vG)?o587CgMY6#*f=yS}!B|V8UDvebZcb}Y zRHPs`_4fl1JvZ~I_w?6Ko3Yt6?xW=kpe^mMSDM7{KxI!qSt8-Qh&zLB7xbaU!q*CA z2{l3|3!jrvHLo}>9&$4hQOLZu_UfHva?YR$=#kTI6*8W>yYhWj=g{6c)m^>E>$FV)6jdUt{}dR7gIIw`V4ZjBT!mN2+m)Y{StH(Dn^hY5%GElC+g z#Hee(O{2-;W_{NvJr8(f>F#ib8Wd<>l+3Psw#sye$yMs^UT(w#6AnureANF)nGQVB z|9m#qCCdjv14r9+5Qdi|w$&dk1Qs&cOiqs-Zd|0$#{(@byUrucp(EdY$zn;CWW{Ux z8=N%qRP*`BYN+ug;(J(IDL{5%xs@Oc^HuNm*J_k~JT3h6KN@8Y2Ty)vI`p_gaSZ76 zL)|{&lxqBi=3ew3cPG~_3tuo1j;$5&9U^u;L>{XEfZ_Y9v=<=o@(7}mnOeSjIaZPJw3|KWf~Em!3=3&Q9G?}NRQ;hRiw!RaFR zHGg7VF+OJ&o@BYfELZVc&>RU;j2FhzCH$V8`JlA&Gl}t9DYpV)CUP;&>a|STCgtCS z!)<^4L>KL>Ah|0vR_{&WTX<~Y5j+S8FV#;w$M9wA%#!N32g~lo-HfX@_agja7E^u` zN_C&EzS?f?7`LqZD`joC3y&;3-Amk=qOR43qg1ZuPa(cnCSxd;5IYQsv#EkGyxcnP zNA8nG;Uo7u@4K4&IQ4q^IfT4*s_oFb)?FU8{vNq0c0$7AzA1&wMiV38 zp`P}-iwx>2T=EVsJZLdK<+;G$=Y7Xj2C8^~I?$$lx#v>v-dMW>RVZAde|S}su>H&7 z-em(hW8wF zin0rxLf;AxQO}8xwehJvFte9at?^t53><2%?`tEg88Syh{K01l8&_B_NpBo11E9a2 zO*$q-)>#&Y1Ht5mP+G{1@RC^1q~@0F$zKLX{apW@KiWO*&NOg(y|sP@esc>xwpW8Tl=4@q~HR) z2Q>)TR*3s*P+TdFZ2Ea6$xBaf#CH>oKv9g2x9@U*{4AfVx677R_lXX3&xgQMpS(_P?Y-NqwYHM z^!^)EAcF^|-IkU{a?*~_JHtbIPp1S7A2L!QNQRO?4F?SvsrAJU7r!F}r#+CKW?N;b z_ts9vfO>&72xACm1OO98xS2I9STge%_im~SV=vEKxAen^Hw}JR=o1O`ok&>7Y&3C5 z9yds8y5fc0_FItcQ2&?_5AiLO39dP9itkp26zfnRQgHHl7Bzc^+C_vwbtrt=wU!Rk zz3x5xy73rZ8RLKA!@TskZ0Ko(fHDqls&bxO6;3^b6!_wWC^QBn>MEutNRzIP;;=RDezI6`u?&@r!NV_xW_*@3SHvb?60p46_- z;X*pn+F|d&NL#v(GC_u&<*JcqUle`Ar zL?QCsYWXHz%yJhgs;9L!<@O=b?TR3*gLY;W*Og*Igd4S@?@m7xGH2Px>RbG z!4C^<#f>wP42d7Y8HQiL+j^R2I~h`ycM)IoeltGhIl*b54_TKPV08hiK%%&Vy>Ikx zr~Q3FwGn2p^!fnpjqP2DM@^e<^t``YR~IgEQb$ztS=76)YuwP(+7n!|FR z;r2&mmAH&4IXiM!NGGFc0Jljtf8nUp><LWU(Yo(a;KKcAR&Ks++Qpm<0k8u0f%hPg#{(z|!>!%@?HKN)ZI1g1RP z%|t0&>RoFZ>{J!5%V_0&DK5t?j4M_Fp(7>?kO_Z zdOK?UF7{-((ECHh`TJ3dd&mAbavmnSdn-Xn_hhO)kCrQMV++&!5r{QUii16m_nlDM z9B?I+>+QNvzI%APw^rVAcCo(YAv4;OKB)P$cjU(MO%}LJ2e)3B6-!COx6771?ptGF zVMj0PXAFw6%@k3t86_0XNffs3Oy}Qy^tmYc0>%Hr>}7XH6n(O zMFFJaqqqnWy6E*3IpO0{&O*eMERq2>%I2KNr~{Z&`%l{9QbQi13GVfZPw+cQsp?^1eM7a<#Gl*zWr{r-W=|yzg=@4^}Q)@f}Z$ik2C**pjVxy%KfiF4JZfc*1 zTT=)(ZPsvtH#Qa9H&aI>hJ?-98HZ)}lGlq41pRR`uzA{%u;09=*k>}e==+6+j=L4n zRWrms&TYS~>Tp;laPYMEH0*c>R_8Z#I4B&;sn+=VX5`z|v3Fk%X;16yzka5%_|Dr! zx=Z+q3t{4pPF{_&OmAho9~lG}yS?eTO)JUmcN*nX5-M9F|t<2IHYDPInOud9pd zoo;_~zk0Tw;K$XahP#o6iAuAJ#cq7EhxU)ilb0e|6me94`W{L?;a$JktlO_MIkobH zxDIg})?H#b^$u4JMNaKK%k?X_JhzNF^!#$~Xb8$0o*2$L9Q=d<1-n|&t*edjHNQUH zf{nU;Da6sFJ@gIQhpu3umF&OtKC(HQ-K^~dur3p_95_ihM7%&dnVnU)?ZDpV|KP1< zUVDFV_+BZyYId1>OJ#PZ^p1=iQs2l|B=N;lWcuyjVGV2wop%W5rG2tfME9%;;y)N( z+f=9H)p0gs*5BU(vnG5TI4ywY4q2)Nc#l!$>pHC64p^#gYjpj=gXrD|bX|>@<$|Zg z+vK~^vOG0-I_PjxtndZknnPMG56|dA?pqY-Q^OkLW5`{!>`_B)6RdJdSBsuXakBNg zZ#gS6Y*>dcbB$SJYaVTSZEY*04JZAP!`##oIEX!rfy6&tr4^47Qc<^(8MBiL72j}> zm|q;Icy`YiGDqEK}XmAQ7PI>7b`;o|5m0%U&=Sp&T~4({U4&`a5yZ#kYE# z2AE~$RW5o)^=}Q`0Ny=^xyzRqz3L90Tdkw}rqz}oN1J-Mn~74hNAE;?MY23>K(1lo zo!9$NM4^&z=(>@;(r2A~W~V1x?53`+6L9m$#|<;yr+E)WUiBW#lI zU!40cdVeU25PY}&^9A|+wRAaY_Cg!2@o8df=k1W+iuyuMjC^AO-NpS$w2$^UgXmXD z{k|K})afUjJhS$I=S4sRE0coJU@VOyPmE1Ux zW^FP_)P+`W@_h<4@(CFj3MCC;Osxlrhr*?MC!O+7KzA#-=Cth>HONAwnKc;|M!NM$ zs852cci`ahL9SwPiI{ce(aZDhcrB6_Oo?2W8=n}zt&5|09XoS?YFFE-x;}7fjb|)a zs{-IDimLzcgj~;L+={6DLias&%JGRG`n{!)ZE zat*vQn=K_$@+KZnW*>-b2y!T5T6!AeW!_uKdxCsLm;a{ZhNA{P;%uKZDX_=oSK;<^ z-&ED4voALodZ+77c9?F^oaf8E5tWHbaQ3rrj@Y{s-kf z{Yv)t7>SCy**jmO{w`5&aU6Odpd+3=-r8K{g#-z>Krr#zVjrP?DpYD#|Z-us}+m zjJA^#ztTw#Hs&p1z-FkI)hWY2EnYXlTGqT56~%DoSOB#lW!3ojTT zGz&gE#aWuzj?ge(#1mvf>4Z%vWuv$VzxU(mX|*f~Un3XH<(*oylmtfsE3A4jb)$5Bgn=kSuCuUE4Lz8{jP zhhg8TjK9!wEtI?~ikkwzSI&OS@cviT`+QtkDa%FJE+dTa-t6e4KPN0f-S=1{+2Cx} zFYhBA4vp-6D0gyK&X`ZQODLVPNjE&wR;0xO)g$w^icgm!6j)t5^vaxvg6Os%=54OG zV=NdTA>2EViI%drQ?C11-QQ506OA(vv~r)g_sxC1y9-%zb&t4%ZG3MpI%8)j;MaB& z!WRJy?2M{Uch!Z71XF*^L+-b0D_?OhGF<+Tk$_#=`3?iEt9A*Q@LnysBMV}+$d8yx zvk957Oooqrr!jYO@2UGF2pD_6?gbGdw+bWn{?PkO7pt_HzAcxvcQt;oAo^6*PB$BG?XD^wTv8i#S$VcD<;IGY;`q~B~KF!^xpL%kzGD91D8 zX(s{4h-zPZSAuu)+RFvK@BWQma;u?%O4dtuf?x2RomO3wE|%p5oq7>8KddsBZSf;h zj0}Eah_|+~IxJg^)SA&H8SNt^^R#r_Y+6qlQqu!TNBy}R2C(O-4jr%u#3^P z2?J6^Ys(SV+K=#;KuG_qmF*1~2J%dD^BSGcD1@W$IP<~~pdIVq`G`^0*OYPij^xSAo~ z`uGBkVP7^lK29&?%VfOMSuuiPR!VEgySmL!+)RmEr`C8T2UxIgc-5lnnes$i&&13) ziEz^!UkL548M7*1*mkG`8$l;EE-rjIN+>bL~Lau6g~{RZfA zvElh)#cBSnnAN+5Gt}|;jO5KKwLO2blGWp{ciis%ruPK?Elb~93cJ@A)UhCVjr+M< z;6fj>!Lr-Yy~C&zzq~tjFu*lUuHK=|!@fV#`=d;aEKfV?>OK565&%Ssazt4|frFNK z=DDy&3Yn#-xgN>{rf4YNd8mTvi>#H-#L)V8omxEC{}^JL{=; zIAzpholWzN%faNswJ&;Cf+(kE$btTqF_-do?+k|t?77}mJ&@i&tfz+DRk$a6dOu|z zn!L@D2^>OQH9G~C-ru$)_e*ikioZK5+nVT|td#Du{nX#X)l4o}JtwXctv#fb_nsod zRfes!4ufW??0JFqf*W)~v|GeYCmN9S+d7R(fY#d>%(VkUF*XJm;Edq@M-{?-4aPDq z1!+^r>p{f1@>phpgcLV^^AB7wU^n{BAUb(816eT=lU2rp37@i zqFii1*J_h3%j~2Cev4E$l=RNzmxC>fx1{@7CLEkN&A$|KFn)H*1Yx&f*3|`l8xCw( zS_2$EpGccfE+(2D+~vqTW0$p~I6#m5kJeihggVP(3k423#J$6-6v_0q6t(z)DH;HD zkk<0Wfnq&(WYNPU&GB~%oYc8*d@tD9Jyf{&Nh87ZD^PiRNoO?|=AWc`x<-;+qO14P z{8Yw2yuu`#u(x5(fIw!OE`U>f$E}3w;-+yJ_xZAb3;K9Fi`zihWR3d4wV$PT8!V`v z+}4IH#+)({%I#fc?W@1r9a9c3z@v=U^G2>$HEa*%zI0;mM5LuEYUDeW**nj<$P(ol z@9Yh5e3;p^J&;!N(+R0AaPKEQ5AEB2t`9oLwLzBDFEG4e)c48q|Mn9ub{9T>BT*MM z4E}awBz34%%@T?0{GUNs%RPov3T{&<{Pl|{3}MFMLj!Z46j9li5-k2xRjx$xrE#bNa$EzDw z;esy~>(rH!3O`b5P3rCSD#2G+u zwC1VtWZvn?=OB#Er&2WTja2Ee_(P(}n+CQYJng2BXgoJP<9?kV!BhX!Su>-TJnjDT zuMc-Hvh@01aba~07CYPpn_5(|DS)d-a4#YK>PDX$U@q6)yeI9a{?;R4>AKJ${&KBy z9n*J^;}>t;n8{^(5>HgX>f5q|X6yDc>%_)DEg}u+gbfy}Z>t7evfJKa1-#a+6<*~@ zMMimJa&e*;U)n#xDnOsiidvt#AOUzG_J{58l*&-9Y@mIPG`eKxkq&7KeT2rHhi-1@ zN&ob10r$?QpQ5(HA+Z@)QuN`eJuty|`3lb~jji4k-j!T*IAQ|+!L$+9Ak2Yt(iv2- zJZeN8pq%MUWovgUWAS*^Ya&P45R74Xh&-2xKNocMp7Ak~2*$U7{=$6-cMTTk7VYWk z88Hr7z3#vdOd#W~?`J;FaMri_9+L60c>|1hEFtFX0TyCDb)SI3Tc8i7@${3qru0O= z#b=XRcStH9Jlh(^+-;v6=K1z2SB@Ujxi`1DI(&v|wVgj6HC4lI%*AHXx7X&L@jB6(s`6cJ2fuixq{O-@O^`SIwiJ0>BHO*-8 z6tz7)5^@?_uHLv3?vpnjQ#l6=HO2Iv-Zboci8XDx18Ap+`YeX49X6M1fWG3u?Ders_a&Ns6&Kcu5+fMY(Y zf8R95Jrt3Wc^Xf>8zAfe%~A~H@&+nuBU+I|Hxq0nooV>PzjyC=zJPPhp#R~fzsFkfE2CiR_l=JocT|v=!va;ma*1P4YeVR|h1!Ot%@1S>YyUQO!=rkh_7|g)tCa zD!~F-A*(NNzwbH#f;}I$iUI%Jv*ya-?%~%b3AGor#>yR!y~&lD#mRoXb_&W`Yw zQ{T=#Y=^Mrd4pQt>{jcV^P6FcX_i}CINx}-7}bTB7cKMyiR|=tVbKom9ewllOQ^6F z*8P}v&MB1o;}kziy0>EH6arC$<-bar0=!@0s8`sY^)rY9Sv1sc;7lwEIWDVCM@SQ})?D1}*$v?ECp>M*Z`#{UbE@cU_VRPAxV*!u^}d z7fKps=Fa)U;b{OQm9e0;!iobz14UbcFe=H!4S1M7i);dENuwSrOR(9N7_b7^DcNGD zpIsWfJ$td#P1_gmO)v(FQ69b8cGwYjdSb@9htnwFzVyMpqCIgZhjni+?i2UY9e;pN z7Jb=L&A`lvj^+xI8@b!)?n}j1^_(8Y96?;JJ#t4FP)pB?xd+2M*_Mtsq}h*SP!KO@ zchpxZz-TyggbU=TG~;Sia&O>ncP$@WuDp!-$fsAs+PYn4344&FO};n5;Y&n#*HnB@ zrF5p<#oJDk^r<3r7;`(aoxNuDgCMK#!|Fva)x5`?W#Dl!@$d z_Tb79d-&?|3Hg49fOPO9Xmz1Chk|GONUdk^sKc+HH8Xn2t;Mwy2U~-lx5}N`3uX4f ztI!IApwx574$#59d=T?>kWo_xVBVvOTQpwIyy~>+)s@JUEu^ost=D*WFo_ zlHLGrU$U5ZamMAGcvi%vI!R5UA-QU#*>B1&ECLGB;iGbrZ|{B?{TDHfhHGc5 zm|ch@9iE&!O-HIPT-g|_Q=`UR_&c9Qe`dJ?|42K^#)Xr-!OMtBL+e)Y>Qr!9kY1a~ z;0FogsXZ{nf~IWlvIQ11%_+RAV$tEq{kRsa)vyg>t7L-kdP%r}f>}l|R3p`z%GTZ( zmV8~pHIZYBnTt@l^8;gtSs_3ggDXVqK2%eBgwC5*eb?jc>xFeDl|W6sP)i02b~K_6 zsp^j7b$ILc3$*GQ8S0xQ|LIT3C!qQRp6A_{Tr=8VoAum!Fg*y%j=fsPY!_1KDsy|) zp!Nq?N)<1jAfayB=Pu6=SBt%tkD|GYRl5a{9rzc3&YDKtNu3wq)Edt?=o=1?>Dbwm z^^81;BCp+vw4U*@4nHR<<3>glZgCZKaEpPP`-u-6Ye}7fwmF&_(bf9X;o(kAD+xPu zMjU|s*{g>l2VMxghf0kdm?Y5wtoBq3&l*RN_?f#kMVEBF9U_A-zok)fu!qpDHPw zj%RfQl#P*Yq7M0M>hL-d`|ECrY?Dt7?aRxU%lhZBWVg|76@FTWPws+)pHF&P@s#Fj z=BtGAdbJn@-k2SuwIj^HA0bJY$`;G9Q3Tn|jWLm6UJN&JIO0$_v@nucMn7rrAREye zuAGzHu<0?1Ey|04)ZlBaE->XF2z@d1wAkdhBPOEzBrtfAdZARnKB!G=j+*$RzXpWa z?_>Qn-ewQscLQo?GV^lx;*imwKETb}UFl#*{xFqrE9ow+jGBrpS2OeEm({J!)u|!d zN?i=bKZN9UDWvZ2o?!>Ft4BLSu?AZQI4v5;^yx zp<>{)J3Gy|c;?wgH}%3tm%-3*gnn<=@C+wNMu-~EDCN6a8r7kW>WINg18 zi6@SiH4xQ`9C$&yFId7{5jBj88BlISSG zK-LPlyEI^-F)y$V=wMNRQF|c-_RJxp(C@ioQVd| zntT71%-l=vVMRmDr>CbR`tVeTr>qw=H$eOzxQnd6m)Q{^Fy-DKav1fVZVX^&Lgz`nQ&Ou2 zK#s{)y{}xkq|w7HL8SjuFX>yWjmhm2QN{Sw`>ZbXntfvwT)m=qK5da8Y`OuwZs5 zApBA<7S*oJ`ou@eSy5`zFSC2i_AhN=l>?>l8C-Lr;SaWe?XwXOgVU>qSdsz3kkItD zH(a!akEbQo0$45}Z5LcT3A+CBv~Nbm;p9pt0v{A|^YHA$JvmW#P1k~Vd)A6PWTSLk zM5~-ybU31EJTQ53{d=Edxv>GnF>no)z_1H{PA`udb!T17hRyu<^qR;~%Pf{6={kg5 zHUh2orxR#iSck_E&JVP`&w6%+v?1aVp+64}0ab4Of!YqRWns%aTYeU$-7CZ5U>90U z(|>bv5#1Jid)Z%E9ZxC$sLC*8iX3-O#qkW;8=KMpZR^tURJB$E7X4M{ouQtF;k;NiPH z(7o1$KBC^^QH4A}M7ijLp8d~14}LK?jsgM`$RWUKf&cWgHvFPf3`nOM z069%|sCNu5lgl>Uy~A1O%_;E-<*K2v4S^Dpx}Ffg;1=@};w@cH2QOAjbIq7LD2eI3 zlNFUm?`RG(nxJyglMfG`Mn+DHAE`S4H)^`K9XQ3Ww2oU#5I1hsAm1TJdUtsdd!NDQ zYHj^L6?u&cTOG!oGw0rFxP0HW=Y!x)(is}t)&sm~Bc2!E z6XOMAy?>n&G;it7wHVd<7oB{f2W#fvMnCvk1CZfCkDsE(u@`S?`VI#s(z z^@irAPw)2TomyHp{-9q6mW;crU=gTnLB(>k;HYg#u_wBiNJDAQ{uF-l)mecLjkyEe z7TAP7Hw(MjX?WZ>ZRb*kZ1T6MG~y);y{B71G>n z07m6YtR;t4N-A&f%LT~|r@A{kb7LT{XS& zIbI~a-)-g{lRim=yUja!_uaCooQ(g5@2{UAYZ=Ck$#eSN&VDd*mP~P<*Z@l#L4WhU zU)tQ{YiK&deHYs%i?U98e)GkGk`1+&46~xqlY9;syO5uPH44HuS|Yt*Tz|&b);R+5 z`T*VrU(cSQTSVW6&-{&?4cb+BZNu`LE`;9==gpfb5;xhdN87^z_o;|`e|Db?)JrgQ zI`^u3;4Y~f*>}^?o#QtWnLjsBS@!E^{6cbeQb@x-Q%_{}K65oilpLXM5!u zSR*gBHuIUX%o5d#)B4E@ zaNgTlqMBjPJ<-!*X1SIvPxGoQwiq%mH-bJ}a$Y|GKM0R8jmpHj)apoZ15$ zJ9*PuYa+)`VQ?eF++xH&X7Jrc#m0*m4{ZYFAWa%B>=ICvl2WI!q>QgcNO`zGun>nh z=^{cBGXAOib9nNZIR#(lLw^IgzN4T1b3Al-x@;Pf8^PHa98fn)nmN!6Tb!0;fN1e6 zC&zT+x zGdJ&rovtD>s_x^>r=Js5?LlWAk+DWTwsR@s4}YCdH=s+W-|q&rttdv3Kt6WTr;M{q z`Jv5jFV6|`<;(vt-hDVi4H||GATT)Bt9{kB!y}iX8-JFFTDQ;H>STcjG2CErASRghgibZb6=GHg81&LSHWe z+q%PVCsod50jL<5LcNFCwvvvkLXS%|6PDr|rLcD~1ymk4-y~GI?W~a*W;u9wth5qx zt1=1gxgkzdQHEQrPpDw_PVwH@O?Fb+uBU~+c>`k*JL;Ga;r&C64+>m3yY(YLH$Qe- zW5p9ec%$sy`(TB1pHOt+z^;QHAk{Rvaob#u=q67D`SkeQuRvY)t~xL97sI_QT@o*U zqw#Uv6ddba41F=%G~`8%gB)4QDba?9=LQMO>Z=r}ye;iKdoTXFj91TL`g$XNAs}}w z)C}5wDf461X864K^1?ti)#c~80Et880cn`5N@#dg90~B+)j-M}&wjw*z{C3lm{a&2 z1HMVZSFql}Y|G<@ayR?i=G#n56>xgv${i|Lxi_x8@RF~}P9Nu9%s>uYS)xcsZF>#M z&^@QE(cIX07?e3`o$s%w@Qik0{)&iAvjf(=hlE@_u{A6N7Odo{6iK>|pfEHM@5a+A z-4nJ(f%ybNCRgpzPR&kkat!89E8u1-Wdt9ezDa5fb98T0*_yx3elISeQ>T1yf_?0)od~xO4VX)8*G5 zp4~h~+67ifDC@A(TU%4YS))AJ__1kh8DejxEz$R|}{nWLRZ6~E9jX?E`;QomXbQjc{`$>R{ zsQC!~p9$exxP|HmWR5Z>&H0XsDUOyyo4fB-C8~5IMRWDcnz@fZz9YRCa7vfGG|m>i z6;WW(tDB0<(&f^M8j2RQTjqI=KkT!0g7*gYw~7wO+28wXr>5FE3~5vx}XKLhcv?o6lC_rzWQeyEn1#Amskb)PKL|CFGLbr(FKr>9mm#PfxP zxVNUJktdFIlRMJ)*!)(>94Sz&)~a1Ci53`93isRwckL-|^wzI}jqgAPQiXg-+(~p2 z*eq3;b((FqoK)Ut8xN*?j#voA7TY|K{(OLn0XnU_%#vPVlHr$2B&c`w-lyJgke*e( zDeh`}k;!V_WZKKOC?Qr5R0e$oq>P=(6tA4NHgz9^Y7xY9LD~M zF^TwHRfSX~V34Ss0vm6FmQ0QB5Nie2xZ-O7Wlj-UnZQ8IlYw67%@U%uSE z_vz=~DdkdecR&5-*gP!VazApZG;ASP$ibMmXI!6230aO70&LjBD<5lmvYOHJ+&P)g z$Htb~6u465C#JRIx>b{wue7>8v=8I0aAB@?08Xv(4E~Rp$_JD6%sxKB)-$-%KoXYi zd3IjZR+cfqv6*Ayg>E|&^XE?Xs!T$xdp;-K zHK(|hO)g(z{A|vKeW0+3a(q<^WN{$6QcjikWaD{LIdV*u|K;0mxWxMA4BVq*ClgBo zs&|TV_|hRwtV#AaOQv+_`Xl9=+p7zN&43n}|JwUil*iH=;kCA#R+PpehT?OO8jig1 zsi{j`Tg{hFhnP;z76k?;&)z7tZLX&#yTR?LZnUsVy;Bnd8ROg=Ty)nn7;wJExKPxE z987o77I6WfTGGf$lVdG|uz+XnPGt^infp-Bo`KeuYS9K%1)#3xZ8b|R=qBX_T=4uA zke5U6)mxFk0GI7XfAZQhrBO2rrdzS%bKR#c+*YWmMNP;Bo6Pd$%*n9uzLe*5(|hP0 zJmbS-tXltUz>D*iUPx_-bs<5QEBJuJcjEcUT4WwHl5XI`d#ko>gfwJN?-Vh)(tAGi zg=5w9U$_we0ioVrw2pcym+6?v+lHD^Tsbj+81^n+S^+=@i+sag$=2k%qBP=c&QFp- zFC^0pO02aL6+f)?*A#Oli*Rq9^Tj-4-BOfMYMLGA6bDTa71&^}YYiFBk+y z?ZzZgG^-CO*`|Da$GDUa6}KGul6p>FJ?+!E%c|#$HQ90Q(&`+(i@G@r*^80IftT0j zGxNlB&YhyABW>P?_(z7C7Pp2-pW4sdb&nxuI^p6|+(%*MAGj`V?6+i5EidUmWJ{opH$`OxRySCPH@k_JKDzzir+8s543A$Jas}Kzl}hhdH+xd?N}p$27^(0&2z ziuaq1wOZO=b*N21k6B?@J+yPVBX6HLR@J*6-mNx9y>7ma2q!vj8f)WdnYi6)Cp%bQ zL}_4Yhv(3h>{_-hOh#phi=RdxFZ8`3QQWZmtG$M{D_su`gQEO+-hIP}OS`;Ug#pOI z&PBzveKc%t+DyZJE4h;))0uIWqo|Qlb+Ag6O|Gz|V8-VG5ZOH@Y5uhic9~7APBcVj z+kETRQs~S{#|!A-UgMrx_rAK1?!%CZbg-+s@8Vu{*LC9sQIf!!0+q7DbJ?^H08yCX{Dy9-*S(oGrX^#ND6mb%f=#cPSCXrXh zvEH~O8nL$(-;e}X;d^c+nS1$U8}{aTyTV88?H;q8Inyz$|3PQ={YihaUgpwL*Ib$G zW$rOrf4K+k3(uc}KS7E5Kk66y(0}3Z%v)m)8ct^y^F3QK&GtB>HPkya#U7Tnc6xCq zT%KRf+tiD#=M2@@KYI4j_SzX>EnFzoMQvd{r0eg^Z$(`%Qs^l;o?*s?TRATdKB3k# zX1>c4Ul_1WLP=$O_Kgix-PqptT#p8dxJ3OS#2)0))MY~Yp`V#3SP-_`G#PviC~H~D zp(uW_e?(703Aqn^RR8A$ES~@1J%Uhy*ulgm;Cw0vnIL zdOuOE>*t?AWlKZCemk}p~PT=iQgiCD4KAKVR7MfZY#O@Idc9&4L`<9qS zh%ojHfQ(NHTMq*CXHXx9iD|RYe6u9md8FgADQJs6n8637@k507L61#~O|MPK931?z zB$fST@A-2M58h?(vgR7DX75viq%|O=#)U&7x^n1mU`vYAdyoqLWeF1^VECVVFEH@S zvHiVk@PRU&K3XM?@Lqa9ns=`^^cD9kKvD8mzTeMu!JMt;(~}H?kTvcJEVod|)!cK4MN|&^OXCfIWE3ogk_nhhjU^Q7M_qyqqr(-S-A+ zWlE#06UrTNTtI-giS{1ZKWcuNUdQ8~w?C_=m);MEqF}5! zRwRvBf;>}-7+k)bR3fDLUPD+Pz#Iul9qy4UtW~EF{!QIN z->)5rT0kr!Zi6Em@kjoHlH%Mobz76KcP#thT*-?C?9l%0+T!U>2<0owe>}!^CJj<3291bcZw2 z?B>3qq8@%OB8eEgvGQ8u&bF@~+;4+iCVjUMcR;VW6I~a#CodjV@vaCnm$-+QQ4`Ge zh9U3u^_bMp=2&Ag=b7}bs#O1==&xmJeD8ERPzG`a5`( zzm@+t_gKN)>m?M$MP(N2^ICRKM?xC!N1ARYkxlxF^n<JqC_H|zH$Y%{|26I@4*DK%T=aDJ zPx_O`n)K7C^m%N1&9K}zjxy$FeF!%JImI6qY#(try6y9?$;^4X$6RqcFSRSZ6q=ca z*IS(~x6}1!>_lhPp6yO#Ja;xQZ`ZckJAbBz2NqZ3IQ8MBGwa8zQ9tk;;Df#+Xr^~J z50ABUko%E4gUk7ZTF+$68#zDw!mNNw$xqC);}~Kl`Q~z50?D#vYO9#mh!Ka2dnRj$ z>o;1Ki{a_3t*Z4Hmj2=+;E@``Krb&ZD^IEiw+-)n4}5&=Ke}VZ% zz^H^>;N7fb;pImmth+ryEp;D$Jcg|Q@O?aTqxb6%g?S^hZ_07M)w^>0ruTGOQH@$} zuR8HDqMf*>chxjO9&P!c`5&NxVW;1gZ7;=a^Siq;x@Oiu7p~J0*@NSRLjlz8*2i4D zo2on%2g7cw?%s<4TNPNAw!mn^W#x%3^DVo*!;J@VZZVJE85wq%vfo}>!h1i-=st!M zTKOw4Ptxc;5cjpZH;frCf;Y?kWjHJApxh6SmamfKjlu5XZS_teP4B$Oq493GX+Z>7 zaOs$BdA$5ji`HeiL(DJ#s!|iil~G@R(A`ny6PzSFRr!imS)@wRB16gb@dBdAD-T5o z3*Z3UB1nh5zi@%96O!G-7{4|F$6A+|5?eAs;s$vueHJn-Yf z5piUJ9}W&4D69qRY};m10MK#3;_E{BZ{rOp?F-NT!`Ga$wAh~FKv z=D??ij<^Q9^vGAeFHe6IGz#?>IWEJ&%Ey_vvY6%g@|1Za?Z0_Xs&aXkU#XA%rI5ih zGoBwTqv*{$e40p85wJ_7h<5=yCj z<(zNH-3-m~|0}vTxrc+Wjof$B@?Sx#Jd50+8oqCKo;+*B9XBQu8_fGe-JG5su z8T8MWx7bOv8%lfY@ZS(=u39Qm6O_m+94_4;~9L`6os z==5aTeU?ZCfR@{;87G<-+z}^n-_ys%X1<(Kh2iXJGnwa=A_z~ikFvUAALh_|?j!KF zO4q|!PPLi zRFkUDdm!(t0@b5tOM3py#B;(f@6vYIUFb7*hHKIbI~db(>W~#%dm2 zNZ04ak6%HfCxT%*x|z4rn^=u1H}+D$SwJNrzZz|#wPk*;wENeRzGJL!wDO?dnT;0N zk-muUdh{0nCY!C_4^sdP<%TP7>K5vAT%ooLq!Ej2v2{0PP2!t@wrtMBo^r!pk56## zUJnmX)Z0CFOLy;D=g}^lZKfiWa8^)s?&N~IyIX|qF;V9{ErnjFNXP4&M;^$m@&INqHnf@yB z1$Xkn?-8_nF~dJx5tH&uoPpuo`_5ClVrEp_yn7llmZ3l5qci`kuQqX>HEVl5a3XUa znK9=mA_!gEj}ws5ZNVZ}ut zM($zhF6631kwaQT?Wa0d?10mQS>BxV-o!irFOVA;a^uX($ClTqr}tRuVYH!0@XUtC z{Lkt1%)Z|*{}Zb6m%!21zuNaOvJ$9e#*WWiAMr*|`~ZVCriDhh!30#CdPMRs7 zD+u1s=zYPK!?Gh<+8&Z!?w!3?9ZRO&Yl%RI6K)TSh^Tk2D{YId-iI!ilL0}l`h?`h z__OpjdC=MsgpWDfaKuqIn|5sIZ4omyA14{ojd1r1-D${-ad=jy>|4b_0GM=#vF3^qvOFld+P+g<5n-01`AzO_{ibfm!iYlWdQVje$ zWqx$m)xDvNrN&16+1HVRkS5Ho+CkA_Q@9%)Ji;iiRldBPRGu2P|^9)73d+sQHZ1k3l zeaw+nkB!sZeQ_ZY<=5}0m}TsU3*_D!-pNXN;Qi!r*BcSoq#J}BY2FxV5}1b6a)xTm zY!IqTNjFc9_9#abcb%KhyT87+Tu7ULA)vghfkG>|g%7XHwQ^zRo}e0|>j0>StP40R zt>ZcPo>J`%KXAzKr@H>JDUM0waFg(-yqL>gS8hcx6xJ>qJb^^xzEv5c9`SFuL612 zwmYbBHlt#OK+9StI)jY7?KmqXei{Ex4FI1c>U~_j_Pf957w%a2ph8{Cr}!aHy63|3 zu>WiS;RV|_*H}_LHTPAtY7a=>5{n7UQx+`&O`!Qqz<}_<{(Da?0LTtN_^-Z9e*x`j z^j_?Pzop3o(yvHo`dtpOh)fhK*+>*sjuUGw)#IkW?c?8B<-#7;#=q!KxSehki5aS0 zHTiHI-mZ*1P>;T1eYZ}(9wW{WBg6JrjI+}@3m>dV*2xd9Z6FIJ+01dwx9Y5X`5OA; z=uh9Men+f(W2d6uapPv4g6p}Krzw0kVXw#6ef*Q$o3j1uzkbhpi`Cw3n%Yl(#AM6D z{lJgf{YM-QvEAF2yVTekw%Kp-u~OM;A19yQKaq^thO2katg`*geYf>iI~QVZu6Mt@ zBDDYLOeX#cc_M5?vD;4H|99by&t7*VANHMm&^@m6&-mN7RER zyu+`T!k)kW#~O8A@51(`u|_vJqaB0Q6NVZPW^(T#&1264Zd>*wGDf49c3hXEVFRHA#2h zYQhI5dy+F}7tC6t(~|QR*~F#to~%ZZ!j^aQnUZp0C{+=v0vTxUB|DR`ci8M8>qi#a z>3l&b2Ne#T&AZ5~Tp=PuEv?=9eUayPqSd&1=}&-`mt(2_$A&U zyfM&ik&G5e0UK||j}kJh{uiGv%mM0j3j2GZK~UqSMXR>P?yt*_ta2MpHTOvGs$kt# zNuRiaw492jIhH2J?Us4!0C)ccHmi+u*)tK5-L@`vG0!%RC)p77DMHV7BAtm6cNPh- zskO^l@OT&|vS|VvE?~egR!9O&hJf5^V9eru8Fp}wIoFUs^(?_!#OF+sw{s8!wC${6 zGD&}j;y6UN`L?>2IvsB>J@wkAE>O7{f*9O{0 zkrRGhl}5*WJo_WsEn9%x2Lq-Kj;nvA^#PaAdwjYukOFW9^L;{tpeBlF0~))%Zn7hxtr<=V z$AHI+PYnB>vq#tcvPwzOx8j^tf$B8KpOeB1zp_Jb9#z^LI z3Rub3=|-BxbT?%(_8m!kYW`GzVGSMO>xdNq$?z=-7iooxY~%ov>-*e=N5<#IK>E;w zZI4IBGfRVtUK!H6x zjxV=jx%SqrRE!J#;dpBdoHKDasMY_97~(%jFVvhFm)F_j(p|ed=ezp^Utzz;`W1c- zUcBeCH{Mt;J?@q_yfI*0(w&QWbGTPB&(!_y-pl-x{$xEz4zsRl0_E1}uw%uCzA?WK zOzkHh`m6AxCMErUmBSLmzkhwPb7mzs-8QT9FXw}E;cVcrGWQqF!jn~(bh%4N?VKwo zlFnbYRXv|Wz*bJjI}O0TmBW9)nZ4n;k4(>f%@2Byhct(_(wLAR|8Z~N0dZ{k@h(5s z%8858MED1%ls`r1ynvQz^)nava+&y$5N{KXL==;^yg(C&i8GYGJu0E-{bWh4aEub8 zKxQ$iTjq}uTC7gd_spYbF{j!?~t&F_mfVKixM)wL4ReFf6tnw^|CT& zscQoc_c$SRf_t(BhnOywiw*`zYe9%o%=4zvA9pVyDv1jU@}c+y-IZmWCtFyT^zx% z`36*IdD?A&j5_bgCDlLIQmeRarsbC<+5Kq_6}AX1@VCowz5WE_sZSaDyxj@Yxb44s zACOj}dq*7)AXWU;d(RnJcHfA7%=yy$V#gosca?Muyy%3?fz_cs5^bzY%&P6XxO)El z=_E~Wx5ZX_?#W%&*$;2Mk($n^?;cx{BK*+oQLUC?-y!^7bu)8ET~GJT&x7>+|5@lb z;k_??!n;WRMd@QAF&-S6A(xer*xt+$q<$o`1)gGM-ACByDUC~|v!x?O)kJQ(A(!H0T-Al?CU;;Br-Ag7`vvaTiu818D4>T_swkSlV_F zAIo6xGV~xGGv=Jbz3W#20bn~$$#Z&~$jUsq8O-yp*Lk=1czD5ru{@hl7u6&G|C)0w zMK);?p4JW2Xxp{{0?xZ>TXLHsiSyRPe!G`P+W@XSwQJW{R+g{Z(<`~qU*Lk<(l1dG zKZ<@HH=f#S)xfRI4fvZI!z&d~UpsfDD%;fxcES@c^-Enz$e*u`(wi3=*$|N5(Hq}E z7901c$3By~6|cw3bykuCXmJB*q0SH+@#{Xqw&PoGEyU|SKiF8`w=I8m8L@rGQjE*? zR<_U0xqbqA-LO4_;H^A94~6*qK8?M$yPS>}{Y95Q8Xofv|ILfuoAUfcU-Xfjb^W5Z z`bV(4z3<-3uAlTL%?bD<_u`>>6f)(&VeYJ~URvB&ruLIxE+_pX_USkCu7~bF^saM$ zTJ`R_d#s4VXLm_E(?hZv&aY%wm&^~(osCC_tL-pd4dXr5Blk}ojoH6faC?Nc>Ub>_ zzJB!cp6Lx|QGiTLeArGt_&xfE2jtI83p5#zXZEgHwRhcfakHB@XGN5HvaM|da45(g z%a%J)++fd={K4=OuwWJ9L33f;u#;2JGY{SdQ;zxP5b>L{fMgOfdM~(vE;BEKEL<_x zYih@n&C=_>A31fK=bd_9GPx$WH8S2O?`~vLFHMZBbj{#W7|Z-3IYZ5n*oj&tuFhV7 zn08qY-csrU4d@zqzBo!L(bDi_VKZtiK6v z?iVsSwKZ09pbE3R1@fzn*ed);ghz1o9z8yzNIT1JOJ~~zi)YvMMy0+8H31EY>qI^l zu!&0Y>>ZQXlGmB@S?yCM1Fw2daAlXbo;hobjKc^MpPt;0q=2x^@#60`D$4we&K8;2 ziI(2iBOBp70f|9}(dvGKXl-qK(uzFlI7QU8K7@2_+Be5UDM$=I^YTkNy62Xi@_YnB zo!%@oyKwK89-@VGPmuf}(ZtA>CnZC8=qC&eWfZoIRc0t>MWss$);s~a5ct6BUg5;E zG-D)^vyv+mxRS(J$+4KYA>7E_`w31xnCGb8DU)G|;cgjH*t@STEA!ICoK;46b5a|6 zVh38dG0p0Ud|VGnJR~+$f?l75^#h^E)V(rX>)O_BNXp8LYCQ#XH4N&BU+{3|2WQX0pu$O~0w%8)@_QBynz*B>b z8X^JOcA-+a769&MnSTa9bZ%DNY8>dvd}ko2b7<>upG|C8`=cNi6iv7FcZ2Uz&^FYv z+XNB#gV)IC0yKMt!fjSUk`RFH?+ zs6STVSM$8xSFi|d&+K^CmAvb5kVyq~PsCPbgU?mBt^@Q&7{3T^qpHl;4fnhFaU^_O zTUXz_ZooKeWj<8;{L)3+m&I`+4dQ8R_8ZbZgS^)U_j0z@U+vAj?@E@J!@?T|(0t?d zX3^Y*~^+XQ&OE7I5Fg!QWR$!}|TI zuKgH{Caeuxn%H#@h5tRUi(1`Ix(Jc(C&+5Y)@wm>d_2-^nEUpud8kv{g{Yj>{Vls) z`T3>x24${g4sC^!F7RLVs+XMb<{6O;it*N*aW))DFV00x7)%9{awr72RKp+`X~rYM ze!OthdLOSUVuCtMW8@qE59PIGJ&d6i3=Z+yfyulpWL#OV(B@ALs~y*3q%I9llB zS;x3*iS=<-OSbK=bz0%dmHXBc*aq;qlOMF~U%LZD!&Y9IuV2CL3%BgQa95fU65M~# z;t<5++V5EZ5c})Nm7vZ)R$-4H?I+V?-S?R{zW1}>Q{usYr(WKBp&{2@#oc>(TlZ2) zI)2ihlx4lgW0HA`Os%Sh?fynMVwr1;_SAlIr@2%6NuQyq{p3G&@|Ht>%zuD~AxHSv zzBj$Vf!F0uOIP;YI&geVJ9mzI6>TMVSF&+@;Wl+=wZi!KVt7jl0QT)W%ucZ=PI*CxNEqzLftPZt!8<_WBzILu z6Gw`IU1sH~5QCflYa+xcJ=O(&h!7pWO`>-?$}ZzaVmDn?~^ z&!7`t25VC2Y6c>s`TP__tDxeisJoi0nFri=r~Ag5IH(EP0mm+II&f4%iwwaIv+dkr zb1ATyd!~(jrv@9-0WPj8LmK`TlAJ%i>rjBZgyGGl@8R{YTA|5>#yI+OTB3*jvW4XA|PVb zvUnj$u2PCWK1A7mC8ak7_DS`faC4zv+(S(&^sBNLX>W8?_2To<=Gg9$$V=~{#+5@d z6(tNsDa<9V@{b+&wgBtKn%ld%p6tG#Vel(*ucU@wp^kR1qV@yi{bCm16V`jfzDHQF z`a<59TfHk3M`U{H?`T|e&$AkMu8sdGlw<3pj`w>}@k4ZPYmYax#3dvj`nW8n@74EG zo*M_sCu7BmSwXO8x^ykDWX{r#QF&GK;t-W%+d3=5JhC%lHmc7=yz(yPcns?>?a-xB z2-snuESe=m5JG})(liVW1GPOP*6r8DR`4~DN2=4c~l{63Zx@c3|0Ko{QH|G;&ca} zrcD{!^uo2~(N4x}v0weQ9kXD<_>e1^eK~BUW;)87*E)Gv#gPrKVVh-T)x5@``!2Xp6^dQUp=$$ z6z$XH{BHi{cflJzU)=WlNq^FqfKQ$Y6Yxm}UFc)~)y~(L+E1>@Ctnrj@{?!kp4v}7 zaE7P$llLD)``dprJPcpHIcMwZdfsuN!|sr7o*Kt@j`hsAHRS3Tf3lb_`q!!u)#;AA zovOFWVn|AE)zTVgTWyFKfkhWEB1}d8D(GH{yANvJ+kVoCuj3`lKCi;CZM5r z*r5oQ6DQ9_uvHEu^6AbXr{S9^tDSHuWXX8ya(L?1jbe1~{d7jjXd}{r>SiyL;Q_}* zE%D-*?N|97(LGA}V?UYd<-r@5d-V7^cr>`N3u2N~izR8}P&z1V^>H3Uss!!>s8 z=I}dcqzwiho_Yei_+!+gRJ+tUBsT9nu*_E^_D=Pygpj-l96Y;AtiyNY~k39jW)Ao1|&K%X4~ze~g7$Q#w20U7L0wOC?}cM;Oi6*v)0rE%!PvCoW|pVAf|-bAu@Vw-0FkV+&5YD*dc^dv9I#YHy_g>j-_ z_P8g*f|L!%1!>GaqZTkLDh;+r8_c}khTM#U?mW=w$!!C2*L~Ff&?lxcp|uG=EDK(pJ7nku^70?UG-~1 z^fOhw2lWkjyfk5Q=n3SU3(~;z66YM%AD3)c;1J5u=1cD)P_o4d@x)p`5#!zr`PDHd zhTUWwjvZ~j4YEOjdS0gDm~$=B@0NRvV}`S@u3 z&RPb`#i_;|%Nlw^tp8l#@0YCiI*s-*9Hnx7{d}Di(cnzHw66x}z3@e-Z}l4G8Lb>y z2XmG*LxP39Izs?Poii=eN0EA9+g z3{|`LQ}4B-W>x5YCQNBN<7#@G?zoj<&5>Mnq}716ZdYt;0^BL$vv(t|QmB9l{C~LO zr`6WvH$c~R`xa!h+>4u{%fg@@Vol*!$QQ^x+zEF*kx`#YGlsEg>M7^PRongEU-NCa ze5K#`C-5}q`Szpj?T7t0?;e4-7i*x;c|B%=)H&bYcQZ`Zi|@kBcfP6HSZ4xU+=vsi zX5{^awN#ms0&t^cE+xvLJ>S06DMM*mO)(S>jN*h_`%KE zHu-n#e8r!&74vd@Q+OzRZVfftY^NxZ-rdh?tiQ|>jJh0W!=vOmf$L~_>< ziHnlf9PjP7{%w8(R37|z!Y#TJKK$<3dz$rMEn52A{cb%eiyzsMI|X_~x4(~fvwv|@ z4?^aJRcmTLx#W9$^-t|5%~?#}{u!FuPd>!SAmxMK|K$qlE0XdTkvDS3CnAou zbK_oH+)OJOsF%cRpk?LT*b-&#!nNPw?iMWzy9`GzcXD$j3SSS(2lubGzohetcE4N98X;!Oa@%>UP_ObTc{R(2RaF<%AW>%e* zM>`U!9wFDErRCn;^N^_rP1fBK_He!KU0|B#o;c_`ns2QoNiM`7$5lx6E)|WWd19Nw zT>_YS)2>KDC6`ZE?HUV^6Bs93($5H#oK#AZ3ujhnQA9_T>#-yDm#0QE zDtT^8>&+=>k)EHpa&DA2UkC)VTzyiC+>_IG?yEWPzx-#2xAhgRA^C1{${=W)z|$lO zy9rzi4A-^_2j{ndO$GOWqg*PC62@h~t8rKRy8(f<$pJ5(C(k}>2-Lf~U;kjo_HdK* zQtVGNUkp10bzs;PRax@|o7`qvyUus+Fz~=xbt1H*yV(NwAgh~`L+G>MH})wtX0ahm z0vo+B?|q&|OXFg^ywJsjvu-F|A|hoE|KQ@WIa9@d&N zagON!{36_wi98oAoixzIxzoE|yZBk1$93DvqQ6hp-1dH#_|}(Dn&^~zvnrSMm!uha zT|*vuPw$#+?N6c!8*;jjVuevWn5IxXYVNm)|q>Uc^--UVyv5%dW926Cv3aDz0+b|q+7u) zes9=WqI(ZJkVvt&hrqQzHD{08N@dRdDamyYJwUBkv0Sa7jjoGSZRM2pti7G@ z^&l_&1U%hIsJYBJu8AM~9sWtCk{+97@!6IRm^)APSu%Ll+?EoPL`N-!ou*W`Cah0l zba(XR=-@&AhRp1)jfCI0B`nc&5b3_sF1i?HNAo_8&oxAVw0yfx&9R+_+K(gZ7&s^Y z9v^?wdnXyUs^WY1Cozt*8VO6*8>0`>0-H-kSj$gN2^i=-`fCvnZSobd{q^hQ+x`S6 z=i{6Yq9iR{A;#G;71O@4RO zGbiIF7I_|IZQe)hW0E-)f9*T1I;QrM^S_q{uIF*}Og zQ8g~AhPKzAr8hi_qRWna!SCcl?ongT6~EwMKX4acNMjnO`^rh3;h5f4f$F<;V|*J1iy!eJ|lCcdfDsirAe z5oL3#?&yv(e4veU35o1{=zYUQk_`ZW>c5{p!bnfx%i^ndCB&GylzEx;K3PgVc4MKF z!A0fDp`&i^7bq^jN_;X+P47|FxO2t!(($8r63NJiWn6UD3Fx?Z3u)K{T2Uub@s2il zBT!(6iRFdcVcM_FCHsNcBHAaGK=`w3Cy!%~G`R@Robne!rrm=7)8L ziVsz+4{4iJPiQ2AekZk{pWL^4r^;sUF4_=J7F-dgqLr{e_F{(6EgZ)}&#{<;9A&*J z!WHL$n0Kzch{`fy<%Q6PP|q%&`q{#|9)n=VB=rF&=CiTkyP_M@K3%YbD2DUdOb;9T zsdoxnQ+!!WB_2CU97m2*t``4TGi2#qK|Z|`ub*X_T5xzz78<8_V?^?AK6lu7P0(LM9?<@Nk zd@oPfD`WJ+Q5Yik(?iJf=e>Gnx;a0*2Lz;nCGzZV{@_8h6zvC5y6mXZB=0B+Cw^_2 ze6^L24wS@j0p|dKK**h9e8E+Rpm`;BNrdHvE-wAcgl%=$0UI5?;k>5Q zDYPMKQQEnv4<@W1*wIph4Bc6px8^TD?8F%J)XNx& zBIVrVYywd#>r;(V>sAViL-X5ScW}}7^dW64HIUn4Up@@b);pX%dZ&V>ig(eQf$6!G z@NjTEg}r<+EH%BdVzEQwQXaG3vECHtf;;%$u(L$=?ljkga_7*@rQ^GIz5CuPQ4!RE zUi#<}+q9TgXyapdy%e3$Pe#-VWNwEa-D1V#!)IfCmBszej*TP#<4BX98PY%sa(j1M z&D&is5IksCUq4_@%p>`K@LH0c+|8oLHT&USP)$;yhq zb}D{_ydwkM?}DVhrS#%-G(Dcav0S2a4QuDvBlmp^Zq}4K(61!dJ$MYI1{FjQm>Z1* za2GbYY|_^aS7jg{I880bpss=rDLjQaT{@1JVxGO;Ypo7@CRWY07f1Og?4W?RQ_QQs=-!*>deI|&0 z_r4D;i13TOUpY@MC%z#+6?h=f9Ck>s9_c36roB^?F6|!TLomRXR1f(TtBcX}O}%e> ztUL6sRkus2!W|_adti-#!E)Xd>(Kk<2d{w=N^Kx~fYovfeZAi63s3c#b4#ARXW`G* zTt4V4Gv`>IOrlnjt^blt8-YoLgPdAAs2-6(dJf6tA`*=S&{BjkiTNF^wwKjQ|KcsC zm|fUchXrD${c-21o&TX`cVFJS8hJozZ#}B~Aoo>1`p@s9RaX&%q@(!P;`Fr( zjWt|*uol^cy2^p~tefMN5BC@L_|bmy=D47e6GJ|||Gli1MEJ?MtqotK?qiav$JW^U z#$m?1rLn2~WN)+dSvR$xJoN7SwkNh{KQdS4_L;M-VVG{896!l0F;Y99dq!@bu-16r z)IQhA@SwED$Efpd)p<(pj)4k0Rr~xXmEv>#rZ+wd6j>qAFLX~nh1VZy*7FqeU|9R^y=Teg zvF+#GHZfq+Kh2?!1UF!S)@Q@;4!N!rPphYQvFKyurH_?wDO7<)K(%y%Ryo3$jL6ZnCV-Byo9w>K2Df5Mn zrkpO^kN~pVT)^1l+9_7%@XAWECh#TIl|S@OP#z&A8Rrocc|05NLOkEjhY@pPQVqim zKUry5Y7o=y3sI=>(!3>F@xha%=1M7#fY11u%~o*Rdm!g%`Rc0Ed#V|tt#`S#?ZSP= zh*poOH{ll>%=X%3ga;i%#J@#^(jcMF7KxZXzB*J!Is;J`BJ52cnw}b`S4I z`4C6ycMfcBu2Wo; zPN9_<$E^|kR)f4M-t&uV2E(Mdd)@Cc1`ZZGrfm1R&COYI5^az(hXXZZ5HC!DM{!c! zsD-ODY(2`5r{Dg9#LOX}K_rcMk~C6xT40^a>_n`yKN@zJUrcaPr^~FP8Vh)^l2%3@ z%ANih*)Pp>J*LO=LqeY|2I=jf;|E1vtQa_Q)zGD`RTxb&M0mpOV5$YvCmRm51N@NK zagOb}gtt3`CJ_!}Zk?VwKD_i^{FhZ^D)1nPkWEFc4AJA$Y|a0jg`hyL(E#*Qls$WrA?!h58j|;PyRc! zL`jU#7iatQmT3IdP8&U5okoYqE~BnRu$G6sgwUH0{(ZW*UQWUuVMl3^zhQ41Al~L4oW79v^7p04y&?0AC)u`Ksf!2CryQs2IzkW)h|c>Vk>K6s)mNac{`J6& zwGuwdaar)epA&h$jyex{t>DX?3TJr$JMiuX9bU3CzTH}v`)6xoGQOnjlw^=nkHLS^ zK>|Z@cqQS6axCDD)F;~jSF^iJ)4RF%$$fg62;4gN8h4r1wI;J&-OZf*>JEJxxN|MU zy|)m`!y$7oBzyyx3*0fh9y7KV1b9QxWzXJ1*XP-6hTVcYG&qxxwbiqlA$444tNW0{ zia(UgaqP#3U>!fVoo!@A2^dZ}Lvo zTthQ@N&jFSm~$*`l!WP?)XxB{i9~EVb}nuX7TUCJl8HpMT{^mxEo&kal8Nybbqtg}*EckOiY z*Zz>@tj0n<^1?^o_*{Clv%Zl55t6zE$Xl%q^Lk#H4VZp+-G|I*&`#ef7*BU9%=jVS#-i9$@qeqac+TT@G$O21Xh># z@7PGoe@d>FgUIdVkCy$>C4$ABy0^6j1>j0}m2VGD!F~TNe+F278Et^+q=QGmv?4|_ zqyP1|wk3hreEQ$m#yDZ!$8Wlb&PY1nM}uFv=U|O^HuGa+?oS{5wfA@Q{{9vwYWjL` zCf_g{28sNRpk>owH^Cc@Bn;^)NRsH!?}>HjtMo759Ei~ z`!9N5iE?d4vC_4h7tA}2Si8CTu^u=tDc_(hPc7>|j2V3T9+Y-c@?^^fo4wOrD`6(h zXBRSDv)ulw%Dsx@gJhQ|*9i6N-cvUt0EGBQ7>{H_VGqzhyF)O2#q+9y!A zU;r;_Ivpdsquu$e>bh;{(;<<&hW^8${$}qm^b*NH_jfd!dT*oR?1cur_+#b-4C?JW z8(8Mc`MJ8>$)Vj{oDJK;_!2fleFo>iPRYb=xG{%hC>TDfbW2o6cAR zGx9F0vM7Ik)T0ZL;d0ji*By(QpM!KCeCvF-TGHWD$O|d?wPgjk1bMy}Kn-e*0}qXO zJB+8%48-5!P%KKJ_KZVq8oMXaQmi%?wzR>WPMb5v-jZF-;{6^AXQg?LDc}-iDiK9> zWBe4e`T`jS#Z?s1720Of7oTPg3_?(iMxM_Ba%0-Gd@KB_jWa8RcMnhg7M%pB-KDDHrxSQ;PS zA(CO`wV<4510SM%aquL7tO;+ytePb7*l!x{9ymw&ooLjwb0uctarQcbHk%E(6h4hP zeRkFszZN-Ufi3KGUydn%Cb#uz!XGt0_)*j5 z`XO1#X~6(aD3yF49Coxjzlyr9hEBJVP*D+;bId^Ae)BD*v)t|__pK^!E~VfL9DkRI z-xM5=~5vG++-*$-IsNGDxJ|b zee|;#it@WLMOW+I#I)$$rIc~slRLZaDDJe z?5iKW9q0L;FX#_Ho6wLvn|s`i_Om}RRcK-ONg$g+t+*k*RC;(sMlvdJiZJqCW{0?d z-LH-Jo?2wBHao#`cL&(+HN_kyPaQ3Fo2g&)ac%T{o!%JYv5SX~=?&Se*5_{P%usI> zIJ*o5RMAkNrIvXzJ`fC1<0KniB0YlA0wU9tUV14PMiN<artfMI-}qIPfzF#&@*T`q3uMo)F)xb*Ui0Y z*qd+Pa_UIqQ~Sx5H!`)Ktbx(Asr}?lqdvO9Jd;l5@^w4S)!eXG-r3N$PBi3J?dqLs z8UB)+;gIT9qrGBHD|(j80Xxx0mzFxdg;FoP|Cznv*~<#~@O$#X-+HL-%nXXWO2`+i ziWz*QIB)L!;Pk1;X9&BN7!$&1CDaPD7aZa(ICedU&EvBh%a3F3OZn$1z(?t-qDcgf ziBW4iYrty|yAH7WwAW&R%+~Xpt>ha+MX40%9S#)bfo<1B~Sf5Xhb3{rk>eV zJdp70z$YmnP)Et^md9rAuCS)9gWn$e1}+mnmCzpCwz<)}s+!Qxjox9bk5DK;1`RL# zpLzlpW~r-pp?rXHj(?x0yV3hUGP18b%ZEUb<3v1qcg8+?Y=k$dhK_mf>Gg@x3eQjj zHx%%x=<^b4yOoxC@8(JGn?LsEM2^c3KX>yFDU*Q;U(%fkfPJ4)?Bl70NxRbD#NHH2 zDu`pE@8ZxXrS}!(&`yq(?Spd`uxaGO6cqSGq#KANVNdqM#zE=RR5b=E&P8D}BzXtdDA5hQ-{R~QH!rr7&XU+k z_fVrk-~9=4Cy!MIl2bzg>7SxBXJ;AjX6{tnw8e1N#u`%!9A61Vu6hzJ3^&YkSG)Ek zHqwOy4QR6UaLL>%3%b5yNh}o(yG%PMp-@R!tkoG-&Jebn0xb zn`KD-v7zq$qqCQO-=(@~$y0xOPF%eMcFa3V%2M#RN6&;n?9=uuxYeQ9<4ZBNtMz%uOCf21dQ+Kg^#tG1qfIK!yM^J$H z+FpBLN5}eFx*RVLJ{MvY_sZ2^_~~y@6>(q0J_6ww!8Q!5Tv05d<>GQamHf=L~~!=#{ZITdE+x2&HBCmkqugwI4mo@*=bM3_oFZ zJC2qI;^JWUnX#xYY{tFu5r$n$@MRLsl3d`EmVM-W1GwQ|fTGHCz|r>^&!9o|R0n6n z3DMu-e$T$={}KQA!_(PgF+39-qA*_6|<4F*NBiPTs)@hXwb2FVEECW08)tnGG+GD!70m+c{IW zx@`cv-vxYYct`SD;{Q%sns-FE67qp8v~G2Wd~|mRUV6u{mxL(xz(>^#Rk@64SQ8+! zO&ZxZ0xY{EN^B$H6I4`)5*GQuSXg*`5*b(VH~{WrH*(`Szko#ikmuzi`IH!*!o&yb z+sk$Q1c`WpZ-8z-!EYegyCQvuz@GShl8MiBDtln>I(KmGbUNrYKDD3pnVQ;9f{Vt# z#7TW}IQ;fL7B4b-O|R)y@YI*0^8KB=ch98uCd>^p4ny7T9ogss?0siuf%Xm5%mZrglX2qh zXU8t3f!Fl(Z_%WcvS^SQCFp!4nb^g3dTwcKW|)D1LY-P)AUs{Y+wc#tS75vmU4j4< zBj{=trI!}vK3@yL6WF^xa*;_9Td^;OQctAe9R|C}S3Y}69!Oyxj6;(=vc5$HeM405 z3xoe`xDilUq5?;7iqh1LiR~(}ZP|eU#)nl`?sd8TFg+c@E#6^3@}Sx|8{PR4UgWxV19mZpD=L?@yB!=55Y#AR%v zLl=c^R)g-=GDOT$++NDT-OfT7f`wTI)gsde60jY9_UnfZvtlZHt4guatR|m7M-%D?sDO?qE-L7#}@SSWq)wsYW zK;an#_8?2~L{RS_;8`%r*qf~?=y`9;@V5=V9JQ*r%JM{(%5V5-f?ecjc@y6Xd(HSm zb?1zGSN$Ba;^dLGx&7p&AK{5&1z^Yo!ee+VS$q3;q% zHIF4h+BtrC=*W9P2|z9HW7>|zaN4=oy9c?%y)*9V-F;tT-RUcbiQzGsteqJ!i?#gV zu69wG_mey3s6V)?PN}c;)S1aSBq2oXwH-g(qJXWG%K4&ahv+D&T-ZBM=yWk0mB8gLU~-3_?3?owvq`d*LhC!-w^ zvfX!!PQO_eWQ0>7Oz?s zQj&#~ptyU#`hCCW!`l?@a!UWTex&#EJ~sCd9tm?O;v=-^v5RM?EW%#OZ3dZ50Zt%C z7i*9E2M>PQv)h*UH)vtk_xJCdSmpC-33(v-Z58rNLl(Xp;lt&<*4VSB(>I0qo156& z%Kaxwe&$ZDTlF1iLO$pT{WgG9wikw(t$u&0&~pqVI2xO1Ty$-SWrZV2dQ~b2Hjs1? zrh#b?9C-qBBkQvLs=BA1(9^(53gOR>yNZ;&gNRHv>wwmLk@A0=( zUmn@X_)=1waM*IGYs8tK z2xvhxhu)!lYkoRCn4~?wx&ib67wmIvgfXm%ckNoE>R$HL(Thv^2ADg=VNw~*C8?*E zDeiZSQ`g5##nJB++M@8NHg{+D5|jKr&A+_2oN(Q}5H89SBA$k}Hy<8sGfyc-Z#Z^Y z`Ph+U@L~X(azaC@BM|g*b@!yqF9f?FKX~;^Y($GfB&@$^Vuy-D&KlUpk|(s(0I>H= zfji{A>+(W=0=4&db>GWiw^)X0?^DC0w_54+PR&q8v4hpdenZNvo?dPapYHc|opo|EG&7?WI z{z)yXoC7t*04U7eBY7mg8{l|2Aa`NR!>cle2QYbZmH{qQe&|SN6J87@s{L>#_- zvPocy<(;=)_$Y04afC7QB8^z)l!4@prj;y=2YFM$CC-B?y^CnW$172T))U&l5{kr=uT=9#Vg zo`UX&(>`X#JUKu+%F0Y<*ZjHfn5qp@_QMdoOy&OqN!I6=ZNxG2P;zcU zQ`>gk>>Z1Is`nMSbNGABvf=YY3Bf6#SGYioy=x|0prCrkbHj=LrQQKO7pA_M=y<*( zk32R;53kOrmNaq4;^mug69~Cc(TKg{y?yZG4kew})gDK__x~CH1j5r!VlFj){GgMW zizrUhl!T`yEfTz4v87~Y^WVkp8FU1tTRfREqFLCSm=kMHmd+qWKD0tn)`h1+GeQPn%-|$**-|$7w?T&Z3p6CD(+2X$w+#i45 zYBlFDWA1Ox)P53;>K%tBUt6Uo-<$3n4^#WeO)me3;xWmb>`(j22R`D1CXZG>9NpjT z6t`z8meq1%(_^e)T|#@aCE2hS@Wr637|iv-aZWUr(|owRbYM7rR$8dHYP9N+Wbn}+ zpU~lMJiDx#m5bNymS#tY3N^IYTRQM)R4%47`O>c{!`#<$(h0A@g$ztK8)$J3$D z$|TWA#fESL?|5flly98hE#5~=4qIwm3OXV5X6J+Y-OB5FoJ%K))g#y=@~8h+<1CSV zH-%D?Ye>AC*oRqGPq}j1_h~4Iaz<6G#kh3NexLQ2`C@?Eme)i# zo*?sEbaLE>Wb~)~VVR}oe>X3;v<~eYrXgbPy{xYYd_MJlR4mGFfmFHcXeBE7JgBZ? zV`xCV^Qz#G@0U8KalX++i0kORz8hmt)7Wh4`={TaP*IEoHfl8Sfv@7+;F-c!s}IB4 zJKrD#XtWI95sz;Ki_afKtLr$NuKUwT_Al^C7ZBNt6=Ywz`q#iMm zdieut{xJD%NvDczHXXyOft1q{Vp!AAfTXLW-l5>W%4H5JzDj|5fg$GcdN4FfHJDC> zKmQY8)8#?b;X%wm*|Ga{5SIh7EQ^p|zO83CBsmV>xZE>M09oNrd?&y}oGLwZr zaJH}z%M;*^zv^HPZ-pijo=o5-#w6y+{nxw8d9g5wjS{t7o?f(GBI!<{sSK=p8c>;1 zqA2jTK9ev%f`*Y2L=5SBTf1*|D^20WkW9ICAVZWig z<+}X@nK%!4_aPbm^bX4$Iy^2XN(HA37cLO9cYq>tdG%+K95x+Vy?O`qev&FV6Tv}K zU1wuj?{t3UKkZoF81l7=(aoT&y2n=9fI`H43dxhr{V`zEzYn^G{JRcka z?p#&X$J{~l`$rZLIC>}1NzG@koS?e{?-k=3@oxQyQb>i3WTW`JlL>*TKQWk&9=$Z_ zlHzcHa0$mGtRVP4*iN5w++HTgxK|WACyA?OWwoqM2gTaI&HF#(8sgiUh!Go^Rk2wp zS=})ckP{YnIu-|ZnW|Rzw#*^hojf(}s~nCN_cg}dy+(jIUq|=NxHBqBU)<>d(G0e` zX~x_u6`np)CxSGDL-W;Q)Xffbg9AU!iz8D*oEKP7Ip3v)_!ku1G4{=i>|-k;N|`5D zgS}tc>xw(W_Jce3ueuyncX`g z-C>OF8QSRhdCXsX-Ms*6Xi_Fxa;&>v60RcSt9Sq%y-VH)6t&GXn^aS16HFW$M+DB9 zdv2UPOwNC^cb$r?SMRmfkA#VN)~EC+C3P-$jc0yO%t4GtKW!6Q6815ryY^nZgPp+; z#oBtW7UXl3P|`+Wsb1gW-HS_*L1>y|TP_M0sd_*{CJg6P`uenKjaTFCk*}_#?PRfy!1}(CUTQe5W|m$aHKsWlrtHM3!%-(eVfG>? zYdiod03<==$Qt<*?pBEPs5s*8+Fo*$5?iSkFzGy{l)L^EynsY} z>dD=$%Dz8#3qIwJoxu6rcJAu6m-I8)-TkiK1;6lIz46lBamI5U8bV( zRt|?p)#Y;yL2Jj7?%=&Z*6Cgdm>KE^B)fZR6`hQziFJ~$=2sJP2>DTqAV=Laq%p8A zdL(Kq#k$QgRn#uFP-H~SuC1>8NOfQSIb{OIC@-9{#(~*XLoOj5i#^Gyy*Yxti_(d& zt&5CXi5Xxu1Gsy@Az|~z1_rWaXNAkdW#IHn`=Gql{Jlh$RXpB}2h1M^#|I`FLN*M3 zGt*0leMf{7kMBr|5a)L{EdFig$B8JfY*8OQa=KaqKIY6J?FFOBamwo)K6fg6>}ww_ znZ5EHlikT^fS*Sj&Fr?@WwR7id>YC#ht%<(2vDBTDC~pKx$ZB$N8S$ z9`Q4b0pN4eMyJz}Dvy_MaA;`e)wj|6b~(o5>e;DxUEM(MlGg!6ZCCFjkcB22{%E?{ z`v~Iboq`%x8@;C)U!@WTUHv{Aam3SPFLwX1<_R|1&fhGfU9Ej_`LXeM=}+H&4gW3+ zZQD%rI*{EhFfXnjo_;gft#{CE@!5|up7=xlw5&1jTV|&z&LxtkCE|}b{W>Y$hNt(S z;&|1}skt94`3^3ofvr%bCDlq=>N1rkEygl7e_;5(;aYp_(&oR$@fJNL&eL(Q=H=saNQ0Z{08YF z3(Uk~Q#tF)pkmHE*+uM|i|k`n%5krm<>eLKruqkMJ^p|tmO0t!_znM_mzF(W40&Z~ zchhZ6dEdJld_>1%yI~c)961wOk9b_RefV+rkZPyCdY!Foxo9=mW{I>JtSihdfG*GX z$=5B!@Q^?i{a7N}R|Gdh4$(V-aMO`p;B6{3D|ScBy^roPK%afwx<@a{S)Q#s(q~_E z=B;tZqASz3xDThaW&WMG9KS}}VNWQmTd&PBCwQAboAee%JMHD65y2UI!y`%d(}IK$ zTmVf`%T~7tU2?}x!Th_p6Sq}2m$TYPgau5mUz6N~J5k>YRy_9}Rxw5MjH3kq-(?cu zlbIeqhiui*Ds?qJ{li;`%xGM9XG1POt*x`Q6A6eqoTeYa0sM9`3B5y*6R-)rC^yV+ zv-dgn0M-L0jf%6z0a&nx0q|nZb>UtIg*Cv+hnp0x>!_`M1P;IaS)Bmr z?1i*tFhk1)e(L#arXPOZQVEbl5&0e_v)f*7n`9LEO$Q~)RgvG=U8BysGLSQfd~ zpw^?H(CgkgrcLc9TUYOIw=;;n zgFe3)n6pEa*~Zjx5b$c?5Rr_*1=cBs#8%3r)okY zk5)s8#|MfsPyTwlE6b|?(9tN;;9~rmPeYnMTo*lVS*EUsYTf22YXh=&ndfvy)I{pa zPo=J0^EuMmRf^^89k^n^ifpQR9V5mtkmTe{42eGuzR9#sR7Hlqni;gBk>SoHs~gHq zxI8!+f0AGV34R2~aLVfQN(RhLCma?pH%%d4cMG3;WU~j6=&}s}aBE&|Q(3NEVWf@8 zdyrzR|3N^J%)f3Hq6l_*ddT06W{-SKFAp!a?)@s)WuiZx77i*JL;PVl0@^AN(Khu0 z21|n~rpF@!(Y(LkUQi{y3w>X>JHL%LQ3V%P>K*1jMS0r6sRS0g42QNt??dG#agMaG z*q*YcSx*pq5bcY?x_S@R9Xz!-%G@b#`RI)_@$}e1o`Yx(`}QSUAC}r?5*T`0aS*(^ z0$I-(o_ zPaLQ&-duU@wzwF0#e7=ljSVR0k38nYdw3RzQgpzlV?96UKBtLPe+l;BfD-SQWoI8L+ z30pu(ESk|mBx*X@78fbcwPs=SSd>vX4OBF1FYP9s$#Ay*gwV%P(p~Mr8X3p-&eXPw z6Lc5SQj0vPfMR55I|2XP_?@L*LAGwco&lw7LkA;9N^8=F?nXbm4K~+9q9`%ip%t#h zc`_=u&uVMZ_njb6jZ)OI)ttfNj&%9l8U5BUxSTnX&@P88w>!kU%f%m(+~h@{l^Tb0 z7P_aRbFm0V*=gvR<%ijD;UmT=Zyt;i@es`k4G z>_z6=-ZJ!#D35^0kI#M^Z?3$i0S-ku_MU{@T|X&fIZ&lbZYzX)41MtT_4>WSJ`iQK zvf}b^btG6XM;*Br)4$8oxjSVg;C-d|SyI7d?w*zGmul#!y$a~OY6!R*m2ufQHdk3A zO|5}Y{p*icDoiH&l6YG{Ggy~zS2f_7e!nDF#+cG9RC#W3OlZo(ciL6;{qj3VeoHtkv0M}P(tR)PQFqML>OPrGc@(M^t7FZg&-zgtOeF2cwyMhLq5V1una(8$mKbUhMN9u6Sw~0*~K$*8n z-BxuphaPqv_X?E%V-~Rv!{2|vPXHzNM$L@cbmAduUsw?89YrJqk7MB8BN>=U9=`M0 z0!vz4c&*+wJS}}a@4}_a{zDBxwukxb(QJ7*X>EA*PPpMc5Q0zOP@RUa6T zOf#+IzKPVJ8F4d9REdkB9>o(%Uo z<|86i=j+BEuPQZ;N#+@2Qa@R9YCmb@ZOYVsvSw`*eh<~zF-rF*hCl5m{eNdPzuzPc zIXOJ(S$-=oGCcK88jUJ@|nx$E}uJoSJ5pz;%cBz5Jc2* z+O8C}-U?^K>MPgJLQb)wlMywEMp4~s)fBNvbsE#Eb+#TM5VaNk34d}$dv$M3ug4tc z_?th_lBlSysC_U3QGtcWmrvH+pFkk&sS`JI=ZqOm-!`H6Xo_IGw$f&`Vsl9BeqPCN zv3S!^E=k#sr)C!P^HGT49ms8`r`J6_5IqWW(_>=%gsX;01*oL;L9`R2-ZASZ$gU1Rq7TUPMmA9AFIqFc@jNat3gS+p-qO9W~sG%I2djqS|Y*;XQFF%v4fT z+W-BYZ-2L)>D2G44JiB^Vn89lqY+;s2^(U9x(4elY{62(+pxpMQ!}f&rJBN`Cu#MN zDus}xpgnEPThN}GrX9T_3pKXsR~r8IMuu?6e9_2HOqHj{d$i)^{RRZ^V@BS9dTyYL+OdiUFY+Zd}ibwrbljWeN3lv{s0)eu=bz7Bj8(Ru?x z+2$D#HA$jS?$pW60ift#h37+V?2^u9A)8X{)~*L~_InjYw`JB{@2_X~+-3 zhJ@FQgt~J%REY<#q-9Ty_LTKrLQ36UWJ|{6sXO?3n0O0w2AX5|dyUc#br&g0n~9p4 zjfFRNRNM78hpeT?oqrU+*lv=6ndI@xXA7*%x$q>|x1>1qwU3F!y(`YOaSzE1kR7w- zG}QP%RwoMAIJ73gNt*wqW(mXA2%*|g-1#V05&tdL-w(t@9Ze)fetW-;rL*d$(^j{9 z={4RB5Ru)JQYgjnc@0-hwEF65_qRdy?^l;Si*X8%tL}Ga>^vIoo8F)Ik4Kn27l59E z_d27yBS|t0WhWt(hOASDGV?ImXadEBk;r^(CTPQl+dQ<^@|o!_82B)LF*nneWn0wDT)fANm`>c~mJuGF+-&Wt&7GZ6 zCauj%-yYUQM4#04;}AN+hgVkvKW=BO7XGM$JAqq(gO!7D-!0n_|EApAJb2wN=&fX7 z`a1V6lnpo=fHs)+4ybX|+r7&sC&baZ(>^5f-$yQEZr*t%dH)oCbbsyK+C)3dwVRuh z>U8k%+jT`lJ1W@AfOlBPJ1BYeu9t;cfEc5c1zhG(G`-9ZsfzzL_tE+GkDq$I`k*mO z96>g4ZfDjk$Cj})`=})DtgrXX(HM4Aoqvzv`iwj=YPU>bB{efN$zktU3Y|$!6H~}3 z;5bb@CHqR+QkhcGbD!x;!VqEFzj0`P7{r6UI`)Rg-NMh)8hXTW`}pFaj?WKI=cB{X zR5lu4KYa?9AnW_aBV2ws#<9kNX9#AU*Tw})P#AM7ks&9THXrrC>WxYxm1CN(pd#56 znq};iE44;}PO^VvlH1Rwa>eAR7>-RV{1O+{+u1KwYuv4doL9*8sRln^_^xi1 zxmhIF=wLPE&=h*u4%nJIMTh)OBwzY+Ua;lKkzQmxeidAC%x%PqqMF1K-`rdp(vS(7 zlQXETP^}@qImF%%Wo;1c3qq8u@1$H^`O)eoy;1}$p-fPL+mX0WnR%Sc8b?-O(cVHj z7U!uoF+7{Q(?mp6+=%^&=l2MO}Gwm26&d$=;~RMM93^3#9l z-H5z^9HYVN$D!)bT&y$|o#bi7EOJ$6_bJ+lQy*?UDTc=vXze)YoRaAdK@SQ4G%2PH zt!AX`rGt0PLX%N3sf)uc%S?zc*U$lI3&Cj1kt&3Mfrq1}d=DafveKoBV6TIoUeehN zw!m6<2NVrj;L0e-9^^1GKj3%keXP{zW$|6wpf=f|9ZcW z$1@1_Aij?{NWPNyPvIx8FC<=4()Qv6^~xyH=5+|3+$F+@L$Xs$V|!4qd!KWH*ALB~ zOuMvo=fLGqWb{sF4I1n{b_nk-XJP~Zj%s^q=v=p*eB}a$hfw^Sx!&~s=kp>lqCQ7fBXan5zOi}M!dyS(Pw#l>vnB!b5F!pU_BHHB(`NU>3KG;^xMr7!?D zud-kddTu?n2h5$8-O2QD-4N%L+34?fGj~L2AFeuhz2L;||8WX5Ib!TRHmgz*6w~y> zW4mrC&f~%f#n^;Hze{JMF#GWE{X-&d$^9UQRn&{VVbC-$?gU}xC6_6j1tbD$=s;bJ zdb9Vm$?hGt9A#31vv&)5+VS4JQr^G9Z{6SL+)~mp*KTegTAPpGT~!1iB={HqtbAXT ze0v`x;N$yI+HSzXU2^ERi9>C$vxhDMr)ZO^20MaXZH~$gKf7)>*~Y?PSL8p>psBYv zG4BH*5!264`Nr&ThmHUJXQ|Rr+QsDyWe+qjI9K=^K_%_`b!uoC(7j!EX`J_jACUXk zgO5}!vMTv%*VHznxatbB3WHrZ1-^J{^Xj{HDN}Ongbm@A5arwZ>BJ*p}aK z_+hKjUCgef+;ex2b+_i~j-;%_An=l%85G97SNCc3FcdDiL|LW(rBx-75lZKmXpS1( znLQr%A@p+hS^QSZkEmU=#d#s?LKE)Vk9~I=hOr~Cd)D_fIg?!VxepurtPy`P>la4)p;?8t$pe=zwMnsl44je=c8 zXan%@{UHJ23SFOM%jDH>Y=$w|yH@oc1B}R1a7zO84#K3(>ELy}akUfR-u3A1BenIi zrzm;+LXEfc$N#|#Msr2L{Qd@xB4UGEzkHl~g>>t0HD@D}%l3>6OfoPJfnvG2wJ=px zcBJ?7H?2hPlfKv!FdfJ1Nh3yG={N-O?W$c(Wk^wsFF?);pI^6o217=^ny-_;xTL7WmjlkKWpUp9!Cmd;P>c?D3=htnG6b`wwU{4AWy&M;OnyY5*#iH-T3D%sN84rqK4Y?YuZe$1^cANRhmG zE*WTYk@2|77t)QoskaDnOsugqq#+YDhk3E@5VeMkn*!8*uUMofDVLv5d7)fnJW}dn z6I3}J7m41DOEBiqaE%lC7SgeJbItAria^3?oVg?ShRMN@u~z-3!Q6CNcRx-xiErMP zxNT+C?l{~X&6!7bE7i9hGDV1JU_I^vNSLyu-IDMZM{ERjX{yAkgt<2Tz# zL)=Gzre_D$(4d_lr%gv9I%fe{=h2vTauBE7%7_ z1+rOw8s!^&UA$yGF(jhVTbdyUBl9dKn1h=s!m8tVHji-iZ?A=I4X*cs&=k=V3Lbrg zO)ar)om!F~h?y$xB4o9K!W61)gWdyU@f_mm&x z`9|+Em8~^X7*ONc(A2g1x4bvKIY?G8^zInb7D8nFSohfG%5vwlB~JIwXXE5krEwC- z^6J@XZOIaw-4X95kj{=LuM3(CSG6`du|G6q$b9*EVUqSa^nO4Z`RInYdNjdKkm1eN zJqS{_5&=Ic%XSdYoO%qwGR6^@tQg$cAdY8AqdhN)1c(=WREbOneW>VFVD#G;h%Gew z;oS{8IV5dyzHPlEf6gT=XyR49dt03c*S{lc(COHpxFK!>)#fDVPOD$udT7c;i|B>K zc_)7u6lX_KNXPruV(`MQjhRwvJsv1V_Jb6vSxLGVpPE{0ACIm+Cxb2m25@GR?#_fuYmsc2P9_HrnV_ zP*`e-Y%)1J)U$HyNi+jr-E@Je18vd`vRfYoSMLfmE52~g(~GxyZ>w{=Zs_s*hBj~H zaQ}BH=?NFb@FXDhn1Oqtoo7b~goYL-zj_yfAQ_8-{RG4Y@Bt;bVXqZK2>tSBqNsnE z^uGOj$`3~L_ux(fdWUe+<~sQG^lzQAz>w&=4GqbSg7*@wdu=nErmiKYtUQ1bZyk|^ zB9Mr!3BtPZ@!7T6qA$DcyCCqh4m7z=^^SA2(i_La^vic*9)BBs|A(Jsv5mE-B<`yT zQ@Tj+r9dkW&N8vB63_sH!Ebf^#cEyx_`662^j^ znHiKB<-JPq%(4wCd5q+_b~U#?19o%x+qmJA#0Sc*^%(92XE%Y^VZ{DCh9tdjsh%tl zEcVplBi6yad2#1pEH@{i`_N>)xM#T}Jw z_twR>^Jw_ISnEgT$VVOipkCkwQb2WM_5+m&@H=%e_&d?c(00N z1EINzxpNLtBmm3(#CJ{l2c}Cd&|`B8>n(jOzq{9fXALD=GOW+Y@UhO0?p{enzl+0} zA&%4Z&1rZx4La0y+=1NxK*=357kIhg_*@kw!3SE^2a+tjNhR-@`4gq9`1I7wQWLBg z_az%gP-|N!2|2l9P70%)LL_cAHV~D?MMf?ioB0kbxBP{)Wt<%@oGw}n!4SeEl4R>g z^tZUvvNYw|^+%j_T6~)CKFTmm&!Vx@6DNK)|Ne)35DXkXU9 zslM{A7;#?&ITD%$<{+>5zH; zcr#RPA1BB2D~z)57!{4ZOyLUgUcr; zaDxt?*Z>jofLXmSL3+x2nFSDB(gf?207goB4Ym$%u2c<^T@u^J7w7`e%UvHj;A8;d zaiZ0A7jdYri(_=LdiNSdbKubV+qWAF`kO~Y ze3wPJqlNYc%EP&c^)$Q93GnD$v)VGwu<@dTfk&3vU}ddVCC4%Mk^Fqga;(P1Nmw8S z$eEyCde1=jo7j)eD$TLov_Dm$;3;vSlM_A=118R%2AtZPJ&nD(2}h&Ocu$WXbU}Ww z(Z%7%zN_~wF8dZhDubkU!wR5nX$F>k_89KLG)8rF(@j(FfXC>f>lllqlCQCM0=>2J z*}_4Y*H^&I-YcHFV3^;>!iKQMhcP*zKUmi6rTJC&W{VoNZ`ywyrAp2{?9bUHL5_KX zTc7aMI>X9(higd1*kTcOrYk$n(FMGo!JoD@$FF@(e;u@TT+?_&nDfC zdUGmi+KNyv#iCv;P45iad4}LVBj=gz8+D(lefVf3{mt2P(4uR~#k~ar` z(CTC!SUYdUxbV;z5x4zD|0LW@R8!^4Af>Zy;5kB#-l?p~D2z7kq1H>5`>8is0!*=V zGk&E`XE92QY)p93J5=^gKYyv6eK}iE$D_Hc);%|5iFHAu$3>Z&e_3QBv~S)m@mxPY z1J=`6a?>pS8*6@vN4CZEdpLDc+n^?#&mu{&Edv z#0DzH?>Y>H+&yCmR=pLO*AJcn`Sw|3I7{y5EG(bjdM4_ajFJ*1W7MLC6_Un6W3mJ3 z;@#o&;FPR>vXXK$_qmfy6KYpDOj9H?vjZdx4Ayr5xE2ySosg?$L?e*fV-%^X3;Trw zw+-ip{6i#xM_aK)ZNnd-knpP$E!F#T8{|@t`Acd#I(51ubPprwgL?qEFscHH`!aQ} zxa$gDAyO0YCo;++t#RL}t;^HqC^ij>_QhElhTDV+fIppv)4A&Kw%PGag0z&_&*@_VXh;Q~0nY4=X&({QKqp4E9t@}qCy{s@Z>dthMTFns5J^?g?5pemj#-3 z?@4o=Q*`~Z@|!AvnUS_#W!)2XBhI~%kviVUCgU|^j?8Tm>A}qb$l13f z508P5mx*qNY~}!VN5Fzg<&H$yNkTuKm=NxdW?24xF;}AP40cNJ0R5oIDXNp~FvOo8 z4bm|8T5VHzbICaAG(t}AP0@@QYHMJ&C*2LIF!*qcz>gsPjUhpR&)&7|;s~Z6mSooT z>e_9jGT%DhYwxct6x^UBIyylX*<{uBB zvyFRBEDxP}ZTDj0+U7;*fXEdcTi<;BLlBjydzO~}?@KW&) z!D&rMT>(?oV&w0Mz9$O~6o5(eh;tV`d~rP&(v~Oz3^6pgEy>PAD~%69zUWjhk3rST zRJXuqOMjTZK8Wd*XJ{$`=P{UkOEVw8Sbqu!+IiWzBcH}1y_R7+A#aoOk?xJq!aRIYu4^RD z=0p2l5jR_K$|woQnP>`Iq6qU0<(YkYmH71;NCBz|o17N8m`D9p5S`k-!%ei=%Rvst2f5u{3cPt*vmO%iXKiP_L|SdE;dD z!7T-UPte}7&q(^ivq4tuW3@fx64nkYNgf^?0y#7|M0V)@Q$@;J2Z_qN@e@Nr;s{4t z;sh9nuD|{}{uJ2I(}vafG-w}0_fBa{rg78@x(d9fp)8sk`Hf^&w&&^x>>SgA$c|z* zS$c0vD^>ESwcAd~2M+}v%6W(+={@J890^VUU#hB+e`3j>p;^u-d0Cq;-&6H!^4IGv zWV}RuD1T(+x6v8)p5qjSs~V+Bj!CC+dx=v}FuVZv2*}FOkz={Bl@J4MwnD(*R>R$M zZ*CatnXZ^EXLt#;$77botq^6t!T>a_eDQm>Gqhyw*mtTI{k)fOe+vp)d_fX@P`@gd6YdX zIP@;wFSzWl5acSi7|)JIyxR?K@Y$P6QGV|f65mvgrFk;%x6VmYh;cK#vF;GgTtq(q zi*;mMHeA(kf_sdPbW=ql1K}oC+{Pif{8S&oFhQUoq;lkW==(7F?5xJ$Et z^4fCk?CdYjve($2i+=w@Uo61a{gLhXt3L5fCY)I6VNvl?`r5Swa0hQ-qpYDN+%gtt zZck)^^X-VoNM{fq6X>XN-uo@C>-UIwpGZnuYg&#oA@ZGYk;cH4SuDsz$UQ@tUU zFD&Cisf}t}tX#g8Xa3LM$||Jke1848tjh0?ij3>adbw6p?F}u1F&(!}@NYCLruIB7 zO|3=a-0+NCc$sD4w%+Z@#8$W@zsa{~9*wWc{>`{uqXKDzjgc_|1v6B7h8St~oUHX6 ztPh33`cVUwX(Unjw}8oE6ey>2hYf(SQ9Utxm-0igKcCOLe00>)_gWu}i!?s9pZu6# z+eiEqgoIz>SMSmX&zq+KhR2uwb)bz;h)YHN2R@y#MSr4=MYxB$rJ$3!u zlU1)8uAW`2#z-$Ld-95lYFF!|v4?ld>pnRb$dUY zT0g*Y#&H`k*Mk4rXl%1jN!bgiddT)_#1;@N!rMK~MtToCmoz zk^Tn@PH7Frp0p?BxHh6t*JIusCEnOUf)Vu;)TO0)f7J6a3NH?WZF;}uv#q*6mkf2W1mWqudW*R0Kj^O-bE`skCQta zJhXbp-=wqgP{A*{;biwhkju<3#evG;9tm8N-LvfshdZ}kL* z62~E&xqw`i>iz(+9;)V`qE_!uMKS|4_Z#Y0VWKI3LshG1RqNiR-xo-~0cy8OC=ggh zE21T{%>Ab%iauiAZw&on=|KT^>FQ9DHeBmXcTQ)osyfS)%(dN?nWtU{9BQR1uX24+ zhrnWEFF6UuOIl10V$0+b{O}gD>^3pVV)C8v-vID3z@8D*^QPxlfIxQo02Lmp*GdFv zA$LP|I28y(v;)lrkj)Dho_+Vh;qKx6=wc^vCkBpF9Io80$T!>5O$w;;Y}d6P+T|_U zFqAk9_Dt?{*AUzFrfP*@2up@nXo-`(Z>f2cZm!LENFhOD@{WsVT;}H_B{_y9=`OL+ zx?Nt7!Fc%iqEiaw zFJKy|YRYpKrtw3fKH?_>gTP+1@UR_qI)Fx!o61_cJyLi!H+n)lZ2Hcn(czmm)F5pg z+3vJQPvxgv*d@&h_y<3`xc^{*!TqK1U zH^YokM>um4`RX66BVd8)RW+Vi{;KOKk_^KAVsYV?XV>!c{)lGg2^#w9_oL58U)yTT z`VT`DEuGpvWO4hMU9aZ-#?Z&Z$4i5|baiM*tXOZ++p)d-*u0nDf^Xj@EnzoSQ2B<{ z1?ENI?*Q_U`6Y*OvtEChpR)at%J6^t7$fbM^kV z(7o?mHNez!kDlL8&A7r{f6^i7>3C!?RhP9S=WDfh6(7S$lMXWO8txFO;E_4OtbeQP zJ~e{@-Uc80{t3_Yz?xp$46JV-N-_+&z-2@iGEEP0y(V|&x%UV6dH2G7H+K%b+?;vG zYgt}LapBaUk(V4!%Zd91?pDw(xR(-qPu$g$9T(Ca$=;KG20>ZlDb_m*>9UQ&d*GX+ z+LFQ>j|TbB$XvdIxBnM|;kSYNUjEa>Y~UVu-}6fNx0F($+OcKt5i#%h(VC`CL*j${ z{n}`XWP+l1@i5m+=Uq+08HWfb#9jsEFg3{CI|JVlei0g)dgaM=Hhx$zD>dG62NR`3 zLqUPNcS6Fkm#4h8r?RQ{F}Y|7$dH8jH2^+Ag9ezW44R{i>w-o0*z@>q%M>B9pu zyBu|seM}LL2CRS4;=;!tWTV<@acO8hb|E_}L@>w)_p=XDqSriJiDpS^VcfhrUs}u2 zvZa0Ms!%`6n?CVh{-mGuL;n|E`(57l<-X#ZINh$K-8#Y~XVF}4Lr*Z=7HC@SV70Sa z$g^h_xMT~SA{(wKNr)daoFHSHtjD&xskW9(MWH)sWidNH#e>fZ+DOO4WwPZq!*Sz; z3R?Qu-qn0Aoqz3WUAsQZs@7^%<-7MsMV|pLKL*3DNi#uV=mqiaSVSE$yP!nOQgt(# zjg1Y-J7QTssn5E{gjpJ0N-H><*DKAC$L8f!#1Ho&q{ovO^jptT>&1HYi4xRHQHJ!j z5Lh2hOOD{DK+qD4c<;Ow_)yZX@Vos`Y}MJln5SmjN-KZ(9@qZx504@5W4vda7*b$! z!qj4Ida4(*8mz&Q6O_~%SY;cvRchzt#ntfS=@jM*xaZAFxl+eIR_&@S_vo$sjL+IS ze>ZAZPtVDzdCO=~;y(qUpu3hzN?iJjX9m-d1_5_k71$F(>CdR3R)eZCxJmlb1mrPo zSMtTPHmzDXU3|zm7^?8S_{+=Q5!*-v_ZMV7Jl{4<+oQdrM-*p2j$s^Z8V+(l)x?xS zn^5XB-|5r!idJ;|@R4vxfoGZoI$rYp(v*J-Gjus)K1ywq_)Va+@s8N}ooLCq_FDti z@YGb)!zMZCi8O@de5Nu=j;;1_;c$9)p+G z)zb0bpib|_CkZz8;?P-~i z$F9+@=e-932w7H1VecqABgh&-r&;#2czn3;c-TyWg*#I+sC_?xeT53j%uFjLD(6G#=W-JGpg@%Ww7ib^_GO)ZY-r zOu1p;ACwZw0DahG@~slffS^%Vk(y>Y9Z@$!Y1wjm=j?!7^1BaYx-ri8=pK}&pT!`4 zDWAAxx;r~d{J~x(xn2T&d1`8O^`twRM^(6mB0R#kq!4JCB!Fz!Nls~O`t+{xL^O`J zAcvH>{B8tBaZc+@{hV5Jwsivq0G%RPR-DYJL{hlpXpoae#)t}5bYTF#>O}?BwXDJK z!VJ2+SrM-=N&eI(muhD3vd#45E=%d4+(Ut*_tySKC z$s5`Zwa>=ZL+`(_{4KX%82MSqyjhcPH4|9q%-Lt#B)3v(28cIH!IcAgWK3e_l3HG=^IuKP zG~TKn_69+gDl_7}Xe|{wSvqu|j7CIf12%Bj42^K#ShL?l-dG+Eb`pJ?-4Ewl-I?Rw z7x$_=N7?@3KE_>wZsP6^q;EjFe1FF1>E6h_5x#o8lbWSolvpj`b0XJc zB`W8F%}%i~)o75!`dYFh_QpYM##^=7%O`>`CbVxUpKr4)f6s@wm^(F&SQFYwoY4PeAwSM02t`)3E6&+^u? zoPB|>&GHJ_(EAt`_fY+D#qtqiQ_y?j8@*f0+p#l&q&&~m+Ihc@ckgBGhIt%c#GuJ< z>78jgkKLheaoZ(q>c|pz9g=;p4;vjOpyNBnfk4!eyO-O#!;+2oDs8Puv$#Xu(!+7MzFKyW>M6dWS+gtp$*HS-8q#$20nM6*9{3EK z0B3~_;Laa7?<;bPGK@a4A2u|<&E?C123{L%gctsqaPS^*fYT-pFExR**A3;6G?X`J z+QeFO(u(|)<^jMTi}m=Lj^%`TrO_Uf&AX)|<^VUeH#5v;`a6yp@CkODK*P@4ac^pP z+O~TzjppEM@0};1YZ1aIFA>gZ`$L9+1dFb11q-k!k9P`GjUqk%T z^N{81m;o#Chfq)NL0lu9u%0FzwWBYXbqnpu9MbY|?DqdSCb>;D>+0Cas_Oi7lT0KC zVjaX}fYO&vw|WPZSmKHx^46t&rLXC?RYJ+w9oV}ixPkMqbBufI@qz*H-2vMz4^DF) z#C!NR9Nl*DDBVOkv&1*Urx+NaStyLX6O4ns3U1?B=QVf>nX6-em) zX!LGb%ygu?!@gN21^vpqNAJHHk*x-?Dc=W$1@+^hCC079G2eYr&Xv;D@~8h|W%gUV z&%x`6{CsKYeH<}~9_l?r!AjA;}M8!i&&^+QVSO%D52fR9T17Pi<9IFDj=mK)smY)xzRK zfxd;5m@y>{;42?G6&}IZD}VC~&we0^!m)dJXnWCPSUyQ^E_;WyOMD+dCn}nCsq%@M zbkOn-oFv>aR+m&yxrcGVzA2{pdXoSUqo|8ZI6#*E`8z%DDccfbmN1L1UCO-Qc_$W& zz2x>D>8=l^GZu<%gw)SNYVSEkz&Gk%%uSe1jwm+h1v*veehL^IbWex$Q0}@u9kuV* zIHo)}%{l9cQfSJBD91iBxgA8VsdIJ8JsdfxCy904Ue>;25Sw^cfnv!ML5Nw}SNi($ z>{*sCRCb)FVqk=we>icQ?U-UmoixkV(L0FI98LCeYf1DT2iCoM4Oz#LL%?6EXa%jq z3;dRi$mf^Hx3lIj^bMPje%J#oHl4Mmw#~$I!ilzD#PuZJPAp%`RM4Mz_x4WII(8E% z<+IxUy(f8=-XE&NRbK@>${8t577L8+Uj(~&D)D}R{8qg6_;~d_PwwA#R`#8fvajzh zsE`}x@f{Mi-CljW%4_U?|HCEv79Yi0*V8RuGDR5 zYp%pcPyFVhQ{d^}AR`01@BV=wHG4mV^pHGzU-|Pn50#UDu06M6-!r(@x<}BKAX9ar z)YUE;`O0zOs&IXVE+VH+yQ$6l)EL@16gPzMbsDd|JHpqO1xR=`Ov@6{hftck@U^)k z=FY&~HH^Af+{>|^pY84*<6dG)(}_dDYb9@@YXThv1K0z!z@e!}486oht)+j|4|N{A ztTuM|MlT#ZmQLoTE%&@~3Xj^nmbImA%RPPkK{mD*lrXwTi35Q+SPLU}mCSH0X1Y3 zeeVR{wtoh8-|pk#(#9v5@qD#>D)S92q{qp5jj+P=cae`N?k+HqFcYjx6qPI5ntXt~*b0aUa z?NBW=xghqz5NKV2d|nSRL2G0g=T=^%~+L-N0k4A|J|A<}hKw=Hqx;D@Z{+y5H^ zv?Pmr2@!7Bjs4`UpDD-N!9ylr&VdW=l1k_+%^y~O0|gL zU&aJ>Z^WiSw$%nxap9&(2xfR-WeE8mt=y<(P<{_Cd#|moX%~I>-Y~Cu$Fw%RzeUn} z!@RQs4oAa)<86$meV=UfK87^8+oUWf_YCHnlrqV!-j~=m-3z*>Yf*A+i# zb-DXR@>P@F(z*fEVw&c*>g2?D^-h4HJa)XM3-?X!t##giu;K?HNlP_cFWmORsB2o8 z78|xSTzEs1t5VNP!vF^|_-n_41rA-I+6KTOg4}!gVD(?*egn07eLG+fF76zzwVL|zLu##hj$fM%oL<;8 z>m)Qg0@AzQ9}=9`h3B*kpC<1Yj7^)LPUi?Nd3vXxERrs)p{AExp-f5Nf@LMu;^x#w zZ3%ELt0Cw^bI%?Ue2;IN-?G6>P7F>jSW>M5OX%k4IfXL6aQillgZ#p~WLFv{M+Ot| zXp`Q7a&-pH z%UCuT)03LOu2C*9Nl)u!Mh$$AQXJaQ4>Lcv0)@qQg)FEj7RdW5#* z*YDUm0h@Vpf>m?v9RbvOr5i<9%NXrQ{z}*VLuL+tD;1A|7&;3&&%q-32cph3nDHGE zGaCgBac^b*5c7?`*;3dJQniEC<`87HtFJ_gUoaB%7g9+32%3(fjQQ&W7#7{ieL=EZ zI?Gi-#Wvpn!}i_jNLIL8oC43&OexzgE36qOK+h9$7X#imJ0CK3}kx>wxImU?rSIN!wNQ@BLjv#9i{F4T|?vcASn zy-VTBOqu(cdr-@;={a_^>b^k*% zy>5qF|k&E-W57vnLCxR7V^7Zyb>D-~Ipizy8r* z@n?UNGd8%}QK!;+w``qR)WIdzeI%NXly`WAG*uuWpaGI z(n;kQ!}25mTbGAJ1aE zU6U$1jgLIOu9x6!N*chJKA{}XQ_K6(r!gS&Oh^{;UFVW2?eRwy*O^C6MR^LB=dW8l z&MNN9*m7x&)NGs07S`uvM3#mCdfSIe{ierz*8+z3pW~UQ7ik@(A&vG@Inx+Qa%jba z*XDA#P`ry5p?7``tK{*)#$C&vHD5}e;SO?LadW@H%y{Pr!+PLwcU%kT zXc;BVZ^&FRUPaJqlt0W>b2ZAv3ARW6@XyQ@YI-t@h4cA?F}IzT@uyp-ACIbyioxnX z_r9$173eh|RXdSsbt|=ozrVE*xgDa5SDtg#ha0>8#@@&5H>9~R)1LdqhucO{-xzJ+ zQ~VCP-M-iT7;YSai-;WBIYBS+0(T5t%1SsE z%!vwycw5+eb2|zj09vLvNyyCEIv$Czdg&Gn81Kxp7cLkCN7itZW!By~2Qep4O)BH< z%D4RZVtqOYaulnd&K)gkQMLJ~+JP*a?5X)pK`;bm&cH;y0Knrpp<3~N+%gI4(%5yj zHHF>`>a)&$Uy?^?TRJ1vo@GpNg%eUR`GFKGI%@tZyIPL?@?BmkpdP=AfyA ze`aaHVdrWroF^Fbj3*l&Oj~|@FNA%I@t^+Jl=TFihi>9y!Wq@;yVLJ!%$G5aXxV%I zl#L83K_3YYfxYORxCngc<}K?9LS2rO0_H*y<@dC*LEQN94+{>ImqQr;zl4g`9y=}7 zrsVCNq}gtp>>PicI|?Gp(*<;j>vafDYu*R3e1pYa&@92TPbemye@TH4YHid6IUy958Lw^cQ^bx_ddASjo@&^ zM7`YI@tJWS*bo4r2#>4<_YzB?ueW?KB6D|7nRwnS-mYUo0?M-0f;;|V38UFpKa|oB zb8hZjV5eeSunB!i?%X56v_sDOv5#0DNXX4`hmGA%udMjThq6LFpPF5^UpipZwlzGEe^)r zZh&lXzvXfoMnAd0M}Y5^Jg)LC?B|}f8~R?WKJWf=pge!D42|O*ImU>K;TR)YkI~aG zsETnMwi-GzFQ4}-{@mZ>Lr(zBJu6}$Y#Rym1xwBUTSK-@r`@z+hcMej(U}RiCA{7t zx`>HlBLLoCNU1+T3>Hm}&?h^FWLT<@&Lo(0%tpAH&oYdij$x?xPXJBVSyMjx5p>@s zc!I*@IafUs%y-JD`O2LujZ}^?6~-4Ibxy+U!X{gsd4&Z+qkY@HjNJe3Y}YZ8$R?g1 zB7Me#L&6SEk|+m3GM zXLh_NjwxNet=W2nl`d#5zQiG<7foDm5xOESzuqcwph)Z!F= zJcqI@s}>ZGWcQ0K%l^?=gK0<;gkQIWZt9v$(Bge(K(b7lfXOq&A{CVN61B`r3@e#C zZf>~f(C5$Hapw7|BdE6@EF|bg28fxk0m9!cA7cI%_qZHV_O_we^l)LhQEE{!8*|=M z;<2YhFpodIfuy|ho2H@4&B1l5+zBJU8(N3tKJPLndgi_rHeksuZ>-tq`P*_7GgG#Q zDOWV)6%s7&+ijk6E#4<%JOX%-tM zZ$C3z9vkXY~G_fIb?Q9F_Zg6vSFGBsg`d?3~6%I;|9AEU-hFkFv$@939+&mmrt7wsv2s zZ(`7rgFQP~8S``RmgOVaO;Kk4)4U_DHRen2N@@FlH)0;K9>e}{)+fC~X(hjy^K0a& z`EXI2v-fri0JX--5)G1b(+fGV2FUqIBhl3Nrs3}|Q!(YV`^(@f_OvBo9Y@YBcy8r~ zNicj`rWps%BGPB^$kEAJ`UW|#F*6h$pd15mAX~M`P~_8v^TgMXKWpL)m}55YASRn) zyzMd8?Ol=g40&$k2f?3mXX`sI{o$?piS<#6O75N8h1{o+wx&t247L)o2+c*(Ig<7) zr7V>(^hS0p^O}?653id!!|EVMy4xsLSq?#Uc-Ff;I-6Qyg5SSGDVS2>RR_6}Y#2ZV zT89rugdww|o0>Nu@vosS02Jao&3*X9`=K1%fQH5B0jienxD<|@#dYdl$oAmDdH*|@ zbBS;E14Seo+x5~0yQ-4vT#z=>?3>hlbn8>KKFXe_6-oM(+}9pk80!nf zOyCy$x&ZoKl6=}y8kzIzJ!iznL@zA)J}j3fIjJ6yEu1=4cBPTM*Tgly0LFqHWqu~+ z`Pe>lIcajTNVWTk`W8b=P8vJFZ!eo{OK9(ea|52<19lhonDbL(&N(IV^XPuwIq*r) zM@oWZpBixZIg`5re);^5Im2aLndk8B$vtmUczifxWtq+0C79gm2#Mb>c!T3d(}-L? z?_Nq;EML61hQYJJrGUp1pW}jCxXc=3Q^lT!n9t0;*Q{Oq&?=s|#)P7=e;ZvNowm?& zW%!bKlMwf=nv;0bpVb zUje}Otqiv5s1xl?1U~y!TdS|#4?Cr|eQ&4d4Sp>N)wBb6IJ`fxFyMAyA$d!GYr1nY zKO4yE80Q;J=^T{16&lCQV~ogAzmMvODCW|tqZa>RK-Eu*bKmsVC%)%Rp580kCRVax zBP1rYr3>ed-Awm|jyqXdH^5gFd|1`=_Fy*D#v~x_gqw?2jhCG&Px}xpva#D6z^^jxiO9H)3`} z#QOsqZDdBqgp-44m)%jy3m1%xX9#6_kdiOXtgt5`;4S?(k4GUSN}70Kuo7&|;`gsg zPx^;Mb`mSzg^C6)D0jAd$BYlJ??w z`pU%vj4$mDcS>owycKtrPw(pJ%Gro59~HHxm!4mZ(4lxeb^FkT8BvoYiN~3$;~@gC z;K0+AE91+&L}Cr}NVdR)Xjhts zRAF_a^3I!QPJ~}ONg}9r8x697mSB?Q{;1|P+BatGQE!)M1I~(fnUN?dppj2UX(CgN z%mF?i%KNeRUb1O2OGtkkl zb_tXFS=>9rUs-LPxeYjj-Q;)m{_PkGMH=|`e(C*wiW&w&gnL+RA80`STVSd8hLzWRw(zOuR{+;<4go%*SSW(L>|I;1J)_l7)D`5*Ah@2U zxPb^l_6}?ofq*vW8jOBmd7=w1PQyKQ(`w&PC1ra5(ah@fm}Rj)a^K4Ccy}hY$)W~d zOt`xU{LBq%WDNGl!F{yepTi*F3Z5t<-91*|e9%Fm-b$Kl>mfP7Vdg#RU2da^XdgcN zK^%Z4>9Y{`A-M*1HI{{gkb1qF)$>^Tzm*+ub)|rKmW6eohQm<(ttwF$iP?KScn1i~ z&Zk3n3pA2@map67`-Zi$M6`T1jIwf<^i~oNV)T;>8rs}f0On|0b~Dh?DqWiC{CJu* zq#DtX(IOgBkzlLee#I$f>V$dDYb3_qfoFmg7EZio8i%%l5ii1OcE9((fUT@AloH4CB zEqKo)GYt389$#CJQxGeIjT+XjywHFG81M!A-16Sk$a87^)T5iU!O(~M<-n5m3a;&- z$t%p@R=qE*e9dQn z=p8u;PLfgQgw;H>(8$Z)Q8?7O(t8UM>7CoeS#*GL)4c(}wutj?HvMK8ePJQoy7Zn9 zh8f%e2o))p-udnxsK$eKHc!rYTbz1tWV_EuYe=x^8hDgBf%2gK)bq<9uIwTE#qA;O zC*qY7qbIA~=D15mB7}Th?sj8A_&ZwHC78IKO8e-_tu(vxH^&H2qV)p;AyyU0Iy+8c znxn*Y@O4!6uIiAv|3iM|kzhbGB?#6-SmJYo%;G)m2HquEi@%Rnjk>8knl(D{12oz@ zr$P)%z8IX~3$u;&15sk{^P2*BBWFTvy7G3A%!CRQZsll09jCNwU5`5>?ufYy5QQmD zA@AZob=TkV&AsA|NgXq|`6iATUL)Z4?ACFP&6NZ4WhQcG;bJKIk_{&CNxfSnzLI;z zebPH|>Wp8uI$3cY-oCKJMZ#0+V2lbek8@TxEBk|?dT9vY3gT7RP)3~wp+@LLS{?O z^z1H`<#2Ar1F-aEj}h))xo=6$v|OgtV++29oN z=gxL{etKyuS8T6l1so7aYP=fQx^8|6HjH&uWBZmYLG$jZS-`n91YX_M!^1-i{x|Il>Um1Z|=L1 zk;VI+vPI`wTnUm%q~AynG@}qe^@^{>-Y78|cI*VlxO6J%IIx>;ahZz0Rx%vsdWHNc z?H1n>nSi?o{C@{U8nT4UfGu)*OLt%vPXy{}d&d=G<1Rx(R_7#~6R< zUBVf>?0xNY+8_ixGO%~{!KW*`7=g$l06WmTOms!Dr=E3vcr-}D;K3a2d8+|!R|&*F zy*B&Xl(U2~w?$i?c@n*>Je9I~w>g(1msXa-o-*|Mn#0|%mZl*$L~8Fd?md!-?4frJa1#^+gTlM%-r=&Tzd0(7-YL5|OU_aBl?BJ`v3HG856j}YU9}{e z1o3;)`?KhiD>+Xs*|>4XttUjlF!Vmb7y@3L{KSG&Jepz-cbBzG%1c&5r%$FulU1}+ ztt;@}M|$dGq+V+JbtuK=cdAa2%kkXYB$6U+TZl(sAK=A#&+rQOGVgs<$snaZ!ipgo ze$W7o1lJes1JEb`AEw7*hT^9TVm*Gb=2j#ihl#6Kl&iux5o=IjIC(JR{U#)=qMVvyE121b!MYbX6Ag& zT&P6?G`5L+gR0m5I_dV~H11H{VAOCp0j=0UA-CR|n}MOOF)AG&n?T^=6nAXW<^gQ$ zI?LWiZ?`k&YoQGy&8uS$ngaW~P{WG~&erfWbT@J^h;%-6^EbBshu)bqFTKlh14`gm z-)=FGKd<)!FruE`1FGzfgN|djj=Vqb!H5~})EefC=zgs&UYp+M=#rT02>d)y5nd4C z4>~EHE_uh>&gy*f(<`HDAQPSfb0JHtpN z+^1a2)SWXnH|xQD&RxrScgV)LPu$gPbjLEyt6|(PaBpFK|NV*u#l3;MuW7_pK90p! zjS#3>%u&&ZzQ`inP|ZpkxkGSs6g!mo_Z~kkpLPN?+ds6uGk2$1>35BP*U2}8#j<#6 zd35fD6AS)W+T>ph!`R(I2@*a+;PX!|BWx~bQ%|7g$%G2#zto0=Ub z@E5=~^&S^c^+&d{51uUk!q$KTd($qJ6J#%WWxtq>aAYkN=7kZCaEnD%ko*RqUAEZ>ujhvlPJH;N>=Wi&#VaRSD&h#~?j60y z7L)ZPR`hOZ*tz(at0TLsRfc4@lx_+{%|2JCk>_Xg+adS5x4FItxxXopnBIUMY*P!w zU?$eOf@ao@c04w`2o2^ZwOKn%CLN$4xjJ$Tx68LxioeG!B<#TwTX!fV_O==45U{OQ zaIhjaO(IEhDTMrEM##giCe%G@aG(d)IgFeKQtPZs0wwJ2cRZYjmW5Ald4^OIKXEoa zDi_w7)O10sIOCcJSTCH;C4*@Sv&T}u6;h>ETv2u5(F_e?E?~6wR`~o(?a|8G>E@P- zYHN7vmKf5|1Yw>^EW~2v*w%iTmuNu;-H8|^^diU+^{0KMB*$y8%uD2*(969<-rvt5 zmKS~L9FENw8n2nfIkT!*2Vm?C7tTGIHFUmNNuHh2K8|-F+9k`L2q*^M9$?#!770TU zDbV3DT&_qQ#kL8*ho=X*&NouI!sUCce7o=Z)ix8)RZAF$2v^e0brg@{|7tDxDr+$S z&r{Dd_BVxh@Gqvgr{!yD*3DwntDc0en9c$r4=Ou}@bUX~bFDc~6S(#--}CZ7JE47n zKYBZ(+$ipq`Du_@0a25l6+qBS;?o_6=N76EX{sg2DdoMTA`?6#_6`QIFcLjJu@{(O zw;750ohF>U<8liHfHU}hAmkOjrP);q(osKil$pJ=K*GX!qxbs`tS|MyqQB^!*4UEy z2UkoN-ex%=CLrDGloI7E5!?bD_k;;YNZp9^(I_OQv)pf{^>8+)w*%u5w_;?Okwo2`d%?MG(F*Z>RV=E2QE4o>C)_?Ky}jZihqyEJN65`pSuCKNj*_v=-K-Z zAKb9uLRm<7&{%AbG-fH4^HfjK0v-4E?X31UeKZQ`boWOD4_{wQBnOyEh_xkTT>Z#a ze#fh=-`E;BDDR~Av#h?CLq~c#H37lRhI{WFO)m?PqTkQJECl>m&s$lJz`i79^8G5V zm-`6}XxjAdYI}PFB4*Q#7e|)cP2?RilY{?OIHF~(cgV_>vH$-fuS7pm9=9~vTb+47 zXaB#|DA8XiJaIW$#)N=AbFbt9@*S0c>|c3bAA|bHjAv$vQ3i<`ec zii{0_wr7M!DB-apcLZJ{O6R&SaynbbQgIK83;@%d+;Vr^D@m7sQlC&v)sSY9Om;hM z+{x)xja_lCV$)Td`vuMKMf1i;8n_!&F-`P8l0u}as9%!#5ZT26*@Zf{EJtL<=W!~f z?Ny?Z`{6?PR=U099vMGB6cM@qMZ62{No3v=^tI$OT(j25U4grKO1wA|lGCtsuh&Ij z0&n_on-kTI-hJDx_6i>lbPF4zTodFwhSU7H=$Z|#(r(DJ2teH(3eY6C{>}{mv@t^O z!#i_AA_L>J+9oA0X_OKNd#|k@_x;)(PKS-#{#)K@?+pIMEc_()bFS>N&=U(?MC!0~E3$b41dseEPXJnY>@(O4_C56<@4%e)*^6os|LgGf1~5 znz&_@B8&9`lj|Q_tbv7m&MU^SmDwfZvF)wT!nV0jx@4R#7ybEmHR@tiSEnU~o63;( zhvS){Y**u9sjIP!>2MBdg|F7V7I6)8!2Qsfsqs<$zr8D-k zs98#)z80GVzALrl6!G4X=LoM#IGjGb^L!Q$O5_Pav(}lk%K{Py+Q17 zvL68)gVCk2;eiwq!d#LTq-UC?i~nhO{#pKUAF2Z;CH#(2G8_K96%(d6(kPO6yFs|( zQI#Bb+vn0!k4l?RW5Bx>dF2-K*0fx}wG&wioIRs{J}#b`>XpcfO3T0P8ZT= zn1(b<=Gt#$7ivxu%ZaS5QgW$@SXkcy-FR2QJeo9Ff;MgW>K=$^w1w0;qUMhq3mX`@ zWDFxeWag=TW$$}qM(uRi`Ea0fi#OX1=vJZ)WG;N%io}Lwxv(X`+M(}$>l%z6%$!3P z%S{Uznw=6G{KN$)Nv^-_Hb4D+|8OKEPHWFzx*MMd*s=^SfhWH<;YjnCoVQgxeWO&K zn34vOl=o$8*S$L&@z8DGF~`3LfBe1o0gH^ksSL$y@AnS4wbn>B^$a)Az}Hgo;1bw$ z?S-jzM~DX0#g)MkaMx@$fGb9tl147P11WFFY-C#6!V)(C8JxRXhRGi@<+~ZYY7&l3Ku9;-b2v*(2PahuNn_T?)Y~}@^I(p3UCDPLWN)TzVO&m z-jvxt-cq>!#y*01Mj-TF?%GVaI<-K!oDLJ@?A>shKZjlpW?JAx2v~=8_d({b*F6E6 zO?akxBC`1A*mgu*N^ACx3OODfAz$E0A%B_GW;ETUH{_2FA7ru)T=*6DvVI^q=)KIJ z4@G4)8y;zW*RX~Hg=i4SBisupx#KoK&SLtaC3Q+%1Lcf}spq?8#u~K8aqKwZgr9EM z`EF6@4eEy^4WYW@!)y*7k(HDt!pKj(v;0X@(w6ta!M{FU@Sgeghw^Bkz8_sN`)!TA zs5Uz`JCDQNPaX70Gj|k`;gOkpTY}@91r2Nz7+trdyCtn_zl@N30&NY4`3Mf=1)LX4 zy_kPu+Z=j>{S(`Tly*!$5Z31wF^oo!|5QslJM&;C`|Z*X>4T{;1a&vy4$y15QQT;$ zb=ip(`k+ylQxp|6qrhfdfeC}0Npi^dag+E))3%7TDcmKE5?MedzB|1)gm9k;Q-=({ zAhL&ZS1@|RvYg1Y_jm#W@ow68CA7KGvoh(dwxGxx6tz{nSkAh?S;p<6_d`i;6TXjX z7{R;1J?_1;N_ig^j(Z9?3V8WocOHXgZ&HQyJe2s1+ zIDEGAaAx|W?p_N(WIu}O%&OZvWK6Cl5?Bu%jZLolVNEn&>kOOeCFBjBHo1D*-p9AI znTDx%2Y{^m?<8As4=aaZYu*3YpGUaUyJ;7N9V~VKHk*WCTH!uR9!v53Rl<7PPh~5M z@7?)#4@B$JSxdO9?Cf}Ajb#J6=9)QspM6B?Ro`rDauq6=%&I-4ly|bg=8*c{)z_H4 z@A#)V?|DZ(F#FLh2l8jBFCuQkPP%D64KQ}e1kcGolk7RnPjlU+KyurJZS*egv*~^SV1DaPu!M88$7RTgrKDokeTDgNgrm<7 zcd;GE;{#CU-aEq0GIhsrh7!=o4?SPnJL-taJp-(K=;L93mTzr@OUQ3kn0zK~UCbv77|ZH1 zsVGYq{g96e+6vi<33nzK<|LVN&%W=Pp``)9cqEJVI|&>s~=4hm9lx z=@3m_CK>S?tLSab11n+|;Fbdxw5hgsohbW^a-_`C=$n!ruU+NuU(v@ehjW-Dl~dBmi}$Rt zvUmJ1vc!M*ore;3=235>Q@aF`jJX2qqDS(zEt$7VFmr02Dl3A=5Uj@3X|(;ipCjT`UHz8v zy_impd)_SF2FFBESGIfeZ3-{cD@1IqMu_Frb4m8swg_OdxF|(OS&Ko6CuDYlo#b-lz4oX0t8+?Y7lB7=uoyzs4!Nx)sE8MY8_JJ~dKz z$KK4RcM4on=)Lf@`|9LjJQjrVz$GmojK3k`BqvAI+vkVArk!s8 zZY3R#{l+n9FMdqni3)*BsV)*r>d$|V)7_!MQy{r*!VdHH`nRdepXOlX;GeIhdz-KjdD~@o!8hwT&NE)+Rhuxq}F& z3WrXoPTtzI#xk9J_2!A@5OBz7r;CXx^lXwvy?FIrON%hRDogt8d3N?1`xqP&yNGs8 zk$^IPx?%GMt+jq2gU;C(Q>h_V@VOUhnj#qazw@OSne{uzn>P5as?uc0+vw+ftg!8oh@L_mXTL z2g#`L<$4vlZNh%+T~gkrn^t)A@OGM0YfNP2uOZ!GX@8XKzLx#B;Z9V2_t3c~z{=vi zqvWlxC_o>QSAW-MQ*br+1U1y!dmKE>M;&gxjLAVrJN%Y5dsvd@ossqpmdQ}om^{7PjkY(Juy|h!h{WxWq>=S7YGbKOH_5w;^~@v}ywf}Q zL{Vsga_3hLp!Ui!GY1}%*H=hO?2{S@?XI=@%nET|L%M!<7``Q66I>;x9gSs>0G7Tf zid9G>T(@jNsDPY7ONK^=vqO5@wj~blhx60D8>lj@;5Zh>l}^y-7Iwo;K;90<3HcC` zD{*JqU0P?mn**+0)*dh$)VB+0feA$WPO5k(D5zn!JRDL2mbpN1 z%5h4YG{qMHLs8M#nRmAGMUX_s&03_Lr#Ve6xL@dbjv`jx7S~l5P}cz@^zL-UuH1om z#J?N7{|Uk`5A{wM6L0S8c3Q^7TgnU^#N?7D!fuM|W@1Vglyt%pJpR0wAwXRD}>8 z&we@(hK)K#MNn0N-oG4ZEHxZ64d3rPjm<1)99L#rAD7i)fqDpJ^2RAlm7r8b52G*V zh@!U08ykPRucDC;ZN*Un2?R-U^wqkgJ?#l1`ua~$7-dSoXo)Ho4sGP%NLbdQ-y~}0 z2cDPUd;VhN5}P;0J|WFFm$2|D%m-8xQb_v+UYtsLwzO3xmnuCiSDCKBSSV-B(-L+U z1^#q@e&t>$CP2HYTe(|IT|iy(vqDGOzG^;7&+GWqowM?Hp zIze+H*dA@wy3G+Fu%?#Enff{Df%bDoLhNo&cT(MO$)=jj5BB=tFE8Ph&T=k^v~Y5_ zG!o0=_Qd$JoBe+Hkm7^J8Kv>x{B|UJUwkDJCX{#N*KE4)!iE~t)&`|y*Byl2kGva- z8&le**}Q}Mhx4X6Al*=NVM>6MpjPjfZu@vIN)r}>M4ceV+E-iyqT@!MOKBmi_hZ-# z8r*lZH~8`W4=LJ>`W@_Db=09^QhWnKVti1}2adX2kk;1hac|JA*(ai^cj77!L)mRF z_l`3oXz=R_;NDA@+feUP#kge_QUo=Pw8fMHG-kS|w8hGhFy`{u0^ZsO@~1C2sD*Y{ zy<4cCw$Z-@z7omAn~$10bdWTA013S#ok4+1HLbT9*ezioI-E5!f+n-V9Ak=FkUxa% zea(Ic4-_SuL3PJ|0~aIRnkJ9HAeCS3o$IG}Z8y15j{N#i5h7j-Ae0xAa_{L#e`eIddSa;hr z2VbDU&=GPeRVJJ!*#eQE21Mly3(&pVLICmDahQYT3{AQm7qcPIkbT1LV_9)2`JdpZW?!X z%SaoTS{eum2Ss$+TYmBIAyEVAVZy1_6Fz@|w%cCR<*_0tG^lSEz+Uy*&=;drF=YO> z66UG;E~Zq#!HHW6OM5Rq0T>n))j#*R+R872oK^1@>Kl^UfTszSNWPlZ+TuF8D9s)q z(L2%^l(^x|c>#yE!~0)AELSxidVXabbByVhQ7ygT7H5^#Z$-0)dT#n?W@qGk??;s% z!jS)*H?7EfW5pxZW8`0n7H-iebzmK%5>Bw+|-@Jxlzz_**Evf z1)sT)Z&CMS4t$AK)7iane1{Ua<93xla6fFa6_iuDXRrM=n_Y7csu$T7WjDOk$j#Z1 zCro!I?wLnyF7nD0#z6)r(^!2pZ+eW@$C&2k?;i5 zD>edxLUZ4tcg|vKNAV6r*qc1LW&G*qxTjshujn7_Epto-VZ;)ZFuFH3d~Rwf?!i2& z1W_Q^$)XpgN6k^^eHXub)YtG8VfP;><{7uYql{J^&AGe#8 z8}EO$`>PF)EEaFh0MVrrWCYwL>W>XjU&g*N%ta`a+N>QW?QE4ROtpb2A0zY#9}$rT zUy53HkRocW*QHEsF+rlOpP%RywpbOB z@D--wye?k~ly!PXJ5$;rkHvOgJDxmpy(8m*psyi0e_Jl#A&6rddlO+~*Q zo@#9|hOh_3()aqtI+nFJnT0j;$nyshs7@H|8xIZKO|K7m%w$&Dq!1{ju-FJF3S~~- z*&DZ=_wdGHf?S_!ifQ1PrKE+jjxek3Y4^?EACRbvQNd_pl1z{Y`y{x*LRCIB+K-2y zkKW;*p~*kUX`tN2L|5aV^zJ3H*%M7?^!lTSP%ksp+d%hS{VwoJ*)J2{`t-G|U(&#@ z*WPv2wvdS{3GMQ2IXKQSVN&aMUrI#AzIcnxjr;@}zqUmzllX>}5IEeKczAG{DwvX{ zE$_;K#xD2|~6oca(7A%qBdUF>EmO3NS6t zO!M6&YhH_yp}K%+f_;C^&&i5k%N19EuHuIs?)vDvUqE+^x>hupYR8 zpdO!zEJp5h^C8(aP4!*(1702V$>39-2h7ZrZsN=>pFPt=fGVUKl-WwJlU(dH@(D#< zh|W1&Urkcsp%8>{1)7vDYj3hhfvp7zZVD5bF22sjiL z#nXFeXYBHhlIe-dldCt#=ga7vn6@TYK$viN>jWVp>KvF_YhSz3#K%0TgeVAhSzxty zH2YE~@|$Ywp4*WumJfzM^Np<^Th9@Uk^hacGtooHIeM9K zH>_k$lbsZ}LZOVRb||R+ky%J7f5xkuAom2IlH@X=66rE+9=9GryZD64r{;sL5mn>p zSw~dct_V}Ro}xS0p?p3Kg&wJ=U36g%T5YJuezfIJr=zVRMHdUJyhca%?l#RvXH|mGd+7=;=buDk!7bQM{gC)IGX-mJKqQ2 z9Od?jJMH*pPrc@T+m?o> zHNWV`Z-w`+i+q9|eF8{#wMGG%azq8MvY17`!G=@s|6Adff`Yal zoa^_;9cLH4-McX}?fvu3UmkQk10Gy~fpuiY`+e({FR_U)T(7^tznB?1r^5pd5@3tr zAR>mNm`mbws;UN#zy{iz6gH^wpsHFw|&N2vj@a ze&W=H4(GO0CMZmym1i-jR+}Z}mzS3WfIz>b1=-T69HXUMFm;(ZMHwVR;|mcFQJ`z- zuKH4T^q2L8gg1Z@R^lauHC%4Eq6>i5Qx*>EHEsJQjoWR#1yaXL4DSk&!i8kFSW35w z`Q-Ui(1Net(U`E_QByT10?JKf4i2(A5vF?EgBRI)uEjda(p`ncaWFwvcYCx60qCMV#VyVcUoOC0yC+FtV!s!&%T!FyY3u0T%b)A)71KMURnGS6z!0ds0)GAD9UPsrpe9&3gW62aJy)qpfkh-3Tq=JpRF* z?aQTfSRJ{}M@_+gJOf+jYs??B0G-EHAwk+I2gAMG4+B0Iw?Y)Hp)dBUC)yvhpVy2z9}$@rz>q?8fJ>u2v`lQ&1! zVxj`}S}5Elc1~97F(WsG;PYo=410y?b5@5+d3}@OlZ{KNTZ$h^YPDfKU7a4OUAD&% zA?I)01d5TpK6KIZcP}on>;Cmvwm6pEb-?xd)L}^z?Q}b(w+%LPCZAp?l-E9Q67pdM z6FO?)m5{f{cc~P>)oG~hC>ZI`aQNcM_M&$R_2E--nh|Fjga*5MAgd-j3S1{Yy=M%( zPr98;YPcQaK8dyWZi1G4uHu)*k=c;PtSc!BWGG$rG(RmKJOqJKiWC>l&Z5F1<2S$3 z@)xDN0=Qr70QFOVj* zk-4Qjb-{41!?$+7e#D9Gbf3c;z7EXy0-oe~i~~3-c_WzKq7jakCRbdL(8%4wy*uR| zO}&-`$qblAJr)WSr!CQIgv^J%jpXWCNbz$$QqH--;D(hLsqm+YREnzp6q84{87hQSUJJE-vq{@WF_4rG$zmmN>l2lxcxU^Qj_ z!u21v#}I=?3SP?)&bDMAvPAVEaaHiy?5mpZdnel#AXey~AKb4cynFy{b2iV3PlAlohG0u&#K^4)+(--e?AZ_PM5tuS`wY|lUU16{EeEI zM7RF<8rYqI&$sPBJAUKymDtmVv9{jpuv4-R#P7-SJ2E@0e$~?VtEpafxhb2ER4Tcj zw>TiLY`jHSrSxZ?pv?uWxdx5&_wB<*vbH3-1q)5h7MRzt+a;`hp}D zZ9MdhpYLH?tE=>s=A4C8e%B`21!)_w1Ar#m6%0d7KNy0S2PIsCyi#46fJbtm+ibJI z?=^}K(Y%P+OS-8i)7QCwW{X$<6Nq}L>zrg*S`j3Itx_Z^g|9zj+JI_+>yZ80w0$&^yN7;borX$5o+uMYk0fkPT zK2q2dQ5Uoh6ri0wj&)~m-we6Ix`)Tqliaa1Z&?yxq0}*+^gasgM2ub1K)HwIxu>H! zam8))?e#mHo?=q~`wbkDmj3lOm-91o6EBD3f;c_fSue|$ehwn+wHkTALH4YphS<4! zv)9fjUhaW@?1E&NZ+EQL^u5fQ*I2^pGoSG3Ady;U6e5Y%Dd$tO)|eg~Xx7k* zvi;B=Ya(?tJhEcx5>v3+Fo>a^Bgu@+b~>&M10`*QGx>g@kO*{!!FPsY`$g+~ztoF> z-PAsDnM(FbGo!NToLrpF7!aC2ISIT?T3BB)JVGfp6%bu)X&`9QhI8v-=w>Jd2J}F) zW`VN*AqnsGTg5!`{QjPL2LdWGoFLICQG=~#4sw4mry+5>ygadahT|5;G2fjZx9VFb zvQ`(Pt{M3h=-vn}JNDfxw{E7Y9fjPl+%3g*EUv32Ve2+yq|R%D&^kqj@~xv8_r|tO z_q;Qr3Pc(nYcFL)W-CfzxgznVTN+iDymM?*)4~rX$%T#`nK;w_rHKu%EO3U)^Ml7)f|4A-Vw!^Z6VQsF`=~S+!2GN#geJE{p>x- zI5RUkR66SGfwC>Ny%B(gK%Y(4g`UuYc{e*rGA;}`58Xo8o&XH=c7 zD9du^X99ex0Qo#*w{=U7>U^FOZHt=QnQ$1xu#IblYanMeQ9wjJ0$K5qo@XR}zCUA~LShZ120-OqO?6cn;3xn(fb)#4()L2?Cv>}ZBt*`S?XEPo&opO_-t57 zJ)fVl2|^A>J^-!h&g=Lqs&n$lHsD^YeeCtx`!D&3ZvRg2cM-gZy**(EvD4QBmciRO zT2Y1N@!uB!mJa#D$st=-!M&uVXl&}r%_MK6=q*0##M*U~wD+D>c%-3U)6@e4Bz*F| z^RG`6055d;Y`n1D4<^i|CR=Rjx~D9|@x-TfXd93dJ8zG@;eei7)5blumfoKLFy2_O zTw?FrOydlgcriQF;wb^&>pq%a&^N!8|_+@MTeWXYY4fAbvo&T4)~?Gt*{M-Lm|ZqlDc;xp*412rNgy28_e&& zwz{RV&0BJB*%^^^L(5xH{rh0;QtqS4T*aWdU&wDl$z0bT3j)j%(~OvPWOpKeC{?iK zb+73CsKevOkK!DCM0(m|L_jA{uiGVLF;-4atL?`M$kV!043ln<>i^=Ak7M5G9Rl3F z>vSa@05wP+9Q{D4TJ^*_f6%Q@4u^vq)9D2WvkAxXI&PWlA;C;9$}Wvss7r>QX?tsH zTI=x#S!ZXia@063i0&5TT6W6@dL5MZLm9GlvdlIpFfbcCdSv0uLgyzxWJL$}-nqH< z<4og;pGLhXL`m&nAVIgOA$uQ^rECp)ShYria_L0VZUf|`q$r0yr?c-K*}=BNDMyg) zW+$2Lh}_LB_Vam1!bycZf%rM1n)69(w-fS<(I)Zkz50zTZe3{3uhg!&3$=PY}`#3`1_ccR64VtM~h&gWtZ5dEc=2N{~L zk`(J5R}6-$gA5AWZ<$jv7-Ur6FWZS#8B8M}K8&>j$#@sZIBRFl3{J14CTo&Q#-kZ* zw=;HZ$hdLu#`r+Us#~&2TF|+(Ju*w)jpvclkQw64jJAiAkxwFG>ENa}A6!5QoljEK zJp>$X2e(i*FG@Ji$MGk9J(Ah`wcB>p=uhWd69SyXx}GpsZYyc7KvD1aMlR{@m?gjJ zogTdKE~v-RQRi~n$siES7lfGT_pzS=uk<$T^OF=v4&)kJKDxV+^lIn7xc3w6Tkk_= zKlDC^a5YHI+XW`vHeLL?D)68-C4BzS9}H^vV19Q1PLU#mZ=;~9$!#`BYYF%;$1Sy6 z8Fy}t_L|h!@c0tLP{a*$En&X2&ov>UX>JioglzLQzaBb}z0T{JP-xSFbolaBigNTL z(xoE;T0yCciI9!4a$9OP1l9>sG_n{2fhDP9?{Q@k1YH#1kp`DTD7k2?S|Se*j)^J- zE}b7U+tkp*t?BIUeK29ZRX%!$zukIggnXIq24Q;YT>PfA7h(RUDiK(;?6_M*IZ zMeG721RXp?{Ewn<0vvu=A{^G<5*)>*hHG_hO>6~UZ$q?IH*29UQ?BUj)VA4nQWI2d zv3Cli4?Jp4mn$zpAi@|bUM@VtX&AFBeDI{<5!u)~y2@~ShO^5p@uawyJsVvm7;V=| zqJ3X$nQJ7#J-xPTlkvAswy(cds4P_{KMl0S3bpL|hDi=K-34r*Y+P9+Rd8;j8`NFC zEv)fn*m0MnqHs>*D4^a-!{ckLB`A%PdQuY9(DIOT)1J~l)M@9C)CEj@E@18e{EXQ7 z5$KNI@BB_kn$Z?_wT4reC%9~Awujd#{$p!3qNEH5VWPd=2p(v$F(Bg;^V`wUJxMB^ zUTzz5UwWI|W`nd(lAn&%%KB$|#E2`JH-B`6+tFJ* zFRvTO;uISUEYZw!wNq3MGCSqr`Yf^>Ns_nFK-M z;I-uo?j@8ix|Soo9(k4b&_>tsCodLnOr`>*4-AA&~X=X*4EwuO&q=_vCJ1W%rmE9iU`TLhonTLjOE zMyRLtf?7Az`EBY!s;RNSQBhlQjLoiY<8c=fxMt9FW{h*$C7t6QsCY7F@k;pr)qF%i z?2N6$8ytDb&N6HJu*uQ3JWX+UJxR!?^&z!7g`-lL%bn}t+du{Xu>`Z+VD!nQ{-G*_ zfqi!aI_1rf0}OmM?lO`hbPqkJ?tOEQxYxQ5j6)+JiaUbn6*}=I+x2wc#s1463$7ny zX@$(4QeGj%a_Hl%JWAE$U9dm87(Yxex6*(Ju zjBX!;M&mu$2b+7IbV_uHa$@r*0}08X>L2oOs9e44qtr|ZCZOQSLsweEr08<&HXv~d zwde(oW7yqnSF63Y_o*7_&)`7dHSa5X+3z%wvemCiRpU~OaC0Bw0>y>JVwii*6VPW7T5ZUjb;LJzfH^38)j={qjHsEJ| z37_>d!-LHjMRzm4&JR*Ntk1yaRWuc`Y{oZFuYWa(`QiQxW@8iRFP{#(hwtsTUSI3C z#(fW8_ftekTr-#0*kH%-Z$v}vf5I`(2g|#DRw2KB?#*|_dvB;SxjK0KXs_wHb8aZ- za(IL3{IJ`Ev*(yOH1V6XN^YOHf@?Lwi(QDPY5Y;Q`n2UGW}#ew;LYiY0J1`uggmCf z-%t3|YbB!*zoLR}Zw283#}@>Ek4w&pxS$mVznXkW8NT1T9cb>xZhL0zV3WHv%d)ixA8~c8wiz)Xx<&5JU1P!u4T+1jg1Kfk> z6Wc~8%`3&qki@!X;f?m2eCYg(zQ#~rTzfHyD~LG5hyTQ|_bZU(;N)CthDoqXkoM#f z;S}XNk!{sGtKtTCPb zKHP<9i?P~y#tU1c*qLK)o|wd={thZGSGDEV2Z_a>-N^PttmJV$XBo;%@}Wo zCWX5TVKED9u%k$%4T|rN&PbPl3dx%LW|T5e){NH4z{9L5QaBz)Q(ATgQ;Y!K&Zcyh zsSi;gnM{aNN;5<7Dl5rtA7=U_jwU*9%iskan>3i__uezy#+;}32l;Hl6LfhdSdYoP zgz|~^=Tqw^NWTL%Xzur+sy$HNbhdfk|1+K>aC|^L0RHVgEG=*-`EU7yW2`n4>;Hqe z{FL`bBzH5i2*r`?U3~%u6NrNxifTU;J$R$H}@KMm$p3aiv{@u4NgK^ciHJp1kS->=%^aLSERV( z?$&C@)g*zFLtbA!H>bO~Rx9peq+66>f=X6v3w_L7_sMf_3k_azFCgr0I2DC)0{4o0 zuT<0I{+ulwwH;#+IK*{GqkZRgq$EW8YNdvlMoMIhecYeMZX?gl9emqE@-1_iR zz!&;?Q7C%v%|eH!QOyLGJ|=GQxUR)^;|6EaaFVVxJw4sGnO zH@JM6|1lpWb%rWR`d&;H#J2dfQO9EsOT!2TzFe9K^S>p&4}5C;BGi6nhSaCKLzl3#HH@u1Yz=As2da`>nO>Pb zKdpDClbK_-s@`oET(o#PoqA+t8co@FN8Hj&XGFWBwYPOKazV7;alxOzF{AT@{8fJC zgyCjaov0H$p76N`NjF{KOe3*a?&ij_pSGR&NycL<+J*Ci0a^fdDB?iyLHkMG|GOpH@5!}JfR<#9cI75 zCmmkWRz;RtmmY_(ZY;7rOXFH#)4EgcdT3gn8@;1aS#p%%xpDPw+_gOW3@=SJy{f`s zlY@qr*-o?B`;2=w8F-zJ^X3}krq|WI4xfvZ%$DRo9K#>7mdxG+rI_aJF^2@W8Vt`p zH4=j0)oGsj=H(i_ml>)t8OjX>M}X!U)D zdR)Z@=SLm=tLGoJHLUm`NPzPX^?0s#tvL7l&6_Kx&5tu5ADiB}sa0UpmrDKR0C#7= zft>Et*hqZAr6hvJxM9TkxB{usyG-{8JcM7lU)3yDW8z{Mjyt3G{=xXK04Yy>$(rV4 zevVy0NtnUHS@MiAh0v~m_y1T(1YMplyun*jWY|Bw|zyE;AIw*kM zG%e4~+(&Bn%Q-VQPH!)xPBZN6GraWBomaKNCZ|P<957b2h6}u|j$INWeYH}<=OQJt zHTgGrRo312JyJ|vB|d066V5CPSy!h zsB3zA&2Yo^pDCp-e#%~~Iea(Z$0BpfM2{oQvo*(7>#HlUweAY={7{dJgDxk|l(%~G zIB9J9`ZS9yy(8+k-u3Yn+A-FZ)If3!ORqk>S#$TRWN(c-v%_Dpw{3Ihl{_3l)}Q^e z5PECkF!IUWWo(oC{>5@INg@QmPE0Pvdn{9EuW}XFprTd=*+t&~SEYQ`M{#E)3s1F` zv;TZ*e=cx#D<>=D+9Z6n|AOia&)`nJuvxo;I?ZGR{a$T!(whb4P|d9Mrnrov?JrKFx2*$UPc}SiISy z>fQwdtaS(DbQ9JvfVt4x>fLInoJx2r&AU|98c1(HxSvxb(wLUy`R2p8x4#a z4(CX^UHAk!oO{#RaSGmKFr0u)jL{seUG=Q>gZhb&-G^+j?ZMvOY|3%AW8O{nZ` z`{QBSS|0+{tFN?NrS!r{+9)gF@?^}=n;Z2yE!M#Gn^KQ2*?7(4OFMk?^2*Y6o?OPI zR14$IY6p|FItu|NPo}k-3QSL0w{m~R$J?#5r2_6u_q&jo`tri^T(#`dv0m#|s8)y9 zsx(c=FL^z&Ukk3he7Dg7-+kFGV0%FdD?1tJ&$A3DPpFpggt-?KyE7C19@>`Rx1T31 zK{n6_fUk=@2asKq>`J?$zCFKLerB=wJ z@vv<^^X}UO*e#e_$T-W<9>T0Og4=0{NBL2!8-X|6!QI2B-VTYTsD9rIDJ|Je9j)ty zXxD7^kMq8%Cy`aWiLSh0JCeYQKKN<7HE|wNoNG3J%pcZyvqNVn+ZVon@-y z69;tJw8|$Ox5luM)_~32cl3T>anhU;@F2Vcz<{NCp+QKK7vARsfjB>^_nes$SUMc> zkpZq-E*wf2>O3xBqTYkE4+~?<;D=~?ZKH@)bkN)&3b-Vi6!Pdn@)+eUiEGeQvq6^w zrZl|*`IITrLf2gYYb6hE56u9yxSBW*Db9M%(9|M=3Pm{V!Qr3*z(|jJyy}b zyU_e$+7aSdA-8DYmZ`XHuY)e163}JB)n@>p45tSdZ^eQHmKlc+hu#KYoB;=2_qcF^ zg29@58Flfvz)sUAlZi3Dil(20c=TSYfUrHX(zCKV4TIL+2O;@8s;-8gfo*zUFg3k5 zGTh;AhqW_A9$joHzf3(twQD;BCh|Y#9w^J?SeHcd8Pfdd?0rvYS7tpSMWI&aue$ZzCKs-9Zpe}Md>TR|pc-|6)Uc+i5>*J9_u>d(R;Rx?-7M^e zZSPnRm{_$fUwVugn&v-9@kZ;NE*!oa$~&0zGU3eK^={X^c{z^O;f@0+V_9lE>zNQa zKFAfJmbN!O=Vr9MrbV(|b2*m?>w^m$I3#@5O4MYT_peJSGg2ko7rdL5ODWj`i#J5L&Iz+Vt-_gW*K+E?l zG|V$9q)DE2BbhX`wL3Y}uE(sA*ed!vOU?gzGJ0CMm0Mn0LRa~{oJ4A!l>vbD7yvYo z)69$Bk()vr9vW4_K?Cs0Xj`tnap9oAfaYG_oN_1WGVqouGQZJ=V1V(^o93Q4;Y{yj zO=&o9OWTk2<|VKkXL5A?NupC&fPrw zJuNrD?Vf<|DzHM1^iDz9|0h2KPocxI3p%j6k)yJsHOh{v-Jx#p+?mixMSF}jA+~?} zeq$9)k1mu@M}G2>Z?-a>oKWrPRl8SCDQJiknr&JqIIDXHExn2EGtta<5on(lm^<-mUuITYtI!~ zkwFU0s{)eUm|w|8x39^LrmvEn58s)CgkeK+7!Ki+@fotW;-VhD1(LEcw2oVkZ;=fe zTJ|9j_q4CRS%l!%8(1hmh0o9+Z*--g_1-!OIO_ro05ebiGaaOa3Hp zGrhI=CD+tmGv4(ReG@KMHYRVq6OycVl(1ns`@!MSkaZzs;vIiaU#e-`J^^K91c$&A zHY;jK%ZJ-7mFtDeM%{R%(1iSD+`OFRsA*^KiLclhhQM1H^XpRKzTIMwUM`ky z#{~|hT6+jcw?J-Q0Dg=j>(=mg zH+rv_w^V_-oN@8tpo~%G<)U~G0A)K1;M{fr!>FT+Vo_1fz82eH+{J6s%rr@Nh-7(r zCN9fvSlH^IwHXPkV@MtElKtvy=_Uw|OsS0fMjBK;eXJ!swX$O16!uQb`={^kI)Kns z0K_Kn93=$;RSHj(4WFRlG8$72smR$J}BJOjW9m5)?*<~%MSSFQku zOg!}VJO;J(KW}4jxLk?wC;9!wRbi^1{I;9=_mAz6*I!24*?{Ea6!_)MBCUVNvWK(ZPoTpAZF+M8+y+8mCQ5F$+aTBoY72x4jrZlkdDl79L+dsG_%68^HbNNr? zj*e_V4Cj6vh*TF2-T(zW;--qHi%!gR+<;(PEN$ytg)4Rp*upMJ&3*xx>Ry7KHA*|n z(W?O|;v5X~#=gf?_Hws3%=0}vmHw3Xj)BjB9`8C7Rc?Y?ZOi9LaaYkU6rX;G#@Hb;cdZX15zlrCV=Z#Vw)*p9q& zG`@=2x_jZZGTIcQcKpRw$HgxnW;`@eSqKT13|L1x{#oXD0tjN-l9p(9tA(c0i{ zhmky-aLB@T$om+H4qpd2%`O%hMr(`Rj*CaZb&ne>rqco$+N<%{-_T-+i=%ikpeUk7 zNyv$NB^T%1UY9K*Z&OKtD1mK&tGuf`lL!m>Xq+XTrOnA6lA~rcO84mY4HNP#0GcFz z?94@5p;@IB92_r^6t2jja>Nh6|63}&wUW0|c&jCEIo?uSquLf0KJNYBhu&K>=3q^4 zyJtJgJ3Xs<(bW{W>Cx1x@^tFKT#cwHW~-+8BvPiZUXTkw1@%Zf`X> zc}1~H#yg|6<9UyS{E>lgG0$BaPmV>#Ik!T73J+Xh?bOw$hmEGk>!eELdzUW`8uq^T7n^5u(g6XF!ch(9@mM@!Qc4(sMl#3u_8>32a;~ymBDHYnxY}>=+gqjn?|#ni>yC31Ja> z5{I(B)HJ#gi>&yRz9z@gcsI@%r_C3Ngu8EzU{{rgLX&;VWQ*gZqdp3jemy4EHQl{< zO`_tfyh4TKotgB%otw=fP-$j8eIqkHF;P=SzA%JvK!?ZP!O{4PN2B~c2I(7W9qDMn z$xdrd(GKSwM*ktsUd=sARs$AdT&!~H%T&<9H1XZL(UgHHh!Am|-YcuGU=~EaNOROtQ&b0-igP0YDf_lmu0)rBREsn9Tf0V!~{h10WHiR0st_?x=M&QQqf0wI5M zEd9X@KhC&|`SH9bO?QJ7BuFEny*L1E!`XtgPK`szBswK7%vY)e= z@d~JYMl$&f1>^hOtv!xV4P71|4nt?e$adkZz)ym20CDs|mC3h?DD2q~to1a07_?ND zuB0)SRayb^c|8QrLA7*;+Yp@H5s`Fm0N!C}p&#Nqw(i~{?pS8REcYNC0z3EI-23Jp zx=TL!d5v{%cJd6`NVei^`Ub#CM<1MxwZQUpGOwIC{CBa;{Btnj&&!^k@zJ&y?pcG^ z7VP0t`%d%}s;i_3y(ufXU$E_<5?j&#hn(e-SbIM|hJgS|2It+%d^borR-G#KNe{Aj z0Ak%yn5U6!V=np?wv_VVp4fY6q0ezYO6u@=s&;8@i|Syw>pwwg;VA?Sk|#4xd9{l7l^EtWn!y#AQO zW1oBZuj^s@-GA;kuD|i&^}jy$$4+mt)Whpz?_V4}_Hgq4u)zOydF;b${o=1!>st8! z>$Pkhl&efJ049i8re&o}V+fV=y+_}1fZIf*~QR7j_>~)2n)5s~Q=0=n#1W56yd3l9lxfzi-bp zd=-}qvr0X65%rlCelPkxpwl27Gs;y5U!;8Y?XzAm+q^Cp*~M7*3A+r7Odqex zXrxi2-8x6H(K~JSu9b^^g)OBHJd9;$3kRog=U1H?=g}bI{kk+E5=AE{#5K zsZ|^j)fLSOm=t^&Ql$k~EX6^*TYHC{URQ-L(-diW9peup{6CRZBZQzcY8&Ya2JA*Y{r3)7RMA8)Es%%aP%OZq&`Nz0oK6ZXl+>2d+j&<`|(t% zJKSBq>^FGeZ#sHfoF-GjP|PbBWqp+5XbP3exPRC8QPx;-2Smb{)?JM@01(~c!htLv z>w5|3%fMFHRyJ8)>vI^Z;o6H_a}L%lCl>H~(uhGwGqMI>1=Vqjy!1{(P(l%$IKCCe z(4hxD@By>;vAz}c%8Ht8ZO(Pd=nw2WApk|n{`N+Ua_fYf$h}eRKB~XB@`Y}vQYT&u znT%fiJ3h`O5rri%CN(e9wo}7~_7&LDnw_q*c`Su&$&>wOj1R=p6^+^Eb9-4787Bnq z5#t?r5C!fK0x1v-8U7h42}~bN+PT{s?_(l>WFn7o1m)4?#M#o#F{}s1nd-JN&uiM$L~(Gat;NgmdK2t$FZDeM zHJ~pqV&SGO7$@BmQ557k%*4I5AQbvqH)m{XsUcJLdkTuZ&xg!o{&NeH|Ht^jwWR-d z{qAK=a-+{JFwf+Y*w_R(Pn@ye|Cl>ks`^!sl;UQmNNQA|@tyf~4|IW2c=Ojxh{((> z-ERPQAG4(1Nsg-e`OsmHa#_h6trkgi(p`hH`19N<%w^9Jn-^Xzq^3((#7rb@FlbFO z7LI1fT3Ur6A#x8Rtde+r)^_6QN!np(v0e9kF7Y`;;D5utKe{7bQt>P9WlQjG;vVEJ zpKTNrBX{WH4be!|4%dF4)sPNJR@2!H`ACrvj+x~9!yz0t)mVij$}QgctddA7$U+g7 zIHk8J7_`4&h|}D*)*W{b54N1WKLf8ihrJK;#rIwlC3w>L?GK~pmS&zT=F``~vUKl2 z;6B=(iDv0;?5^A{CFI!ZeY49$2ZS)FEfA{fN%$2l%-SJpBA9rX?{G^UB#3bhf`{vR z7ijqro)=Uw_vUNWAb#>_?{Ed8EAJiJ^=Uw$pzx2u*t|Zk_j&#G@BX_#jlSbg|7xsz z-s*MK^WA;ww@AqzBm5b?H0RczU3n}0)oNsn2Z8_e1Hya941YS*EKvDR9*?~qeBYq) zmpop2T+;EIoyQmbd`JDO9!IqL@BLNZ^NU`{1ETx>-M#Mf-tXgh_uR+*{^Ig}{2n>( zFJ4>@f9H!A<$Dp$CBl8Ya~w$V0`XqF``_^m9pw`AfB~giV|JE1BcrnJy ztp`=EnO~b}#K*>ii$?dq1pif=sJZ>ic&;=Koso`|m#gxTZnmfBg$I^TGVtfylYC_7h)rn`omv`B9v$W&WU# z-A=S7+3TotH1o6P)ED>g-SN_xWGyv3PQ<4%GH-CL`Ug#%DD83`5G0D!-;y(xtz?(+ zMqCrR%H3bMCxtRUqn*8NtBhwS;?e*ej_dV8Q^m*2{ehK0LAX%tqL>hudFg-?t#W-; z;!1B-L!k~*nq}K{sq5cUTT$u`wg)~v%jJoD-i)0RTt$q;*x2j zuLNyutmaUf3>e<%)+)jv_+I<6d1na&*t2>!^oV0oZ@GAdgjcL#v-X6l>-lP)T@#fL0b6g0$04aF$?ur!si zBTxE(>@-P}VUr8s(gkq=!rK5ADyhkWzAZp98z9PQ=EOBZb%I$`-lG(Kq{Hh#0;a)w zbj54q88S|nvc+B(T(WKx^%y9)VXAXN3xPavbJdZU5$lE;U0B}Jm=OseE$=yH$z5<} zt>rN@?;*#7+-n$taH>0&xWbJWkH(S&kQ-c>LEruD)jXQ`t@G5FThfnoAH@?QCh0TE zw`*R#L6WFD>5{&}60rvKjMuGN9+0`aYg^>3?Zg$xZbEgFugTpCWW%^SiA{?2Zx-*^ ztE9op)?2PeB~IxbA{-xk!w}cpwswQCt+3@BZbxzVwfUaboX;mV6ZhljmhckA<+-Jq zcZ>P@JpMKw(96@6Q)b&fZ|0-rHlm*fGjf!JhyIOHUJyFe-t@id`PW*WZjzsfP7{lX z?<42yb0>n&T`c=q-nKV^=*R2ELAQ4 z{KjjOKr|%`^oZ~WW}`$pjzR?+3ILqI`E9wU$H~~&dU(>o!M?#s@xc{95sSp=hk={w zCG7H_DUtG8P%hO}xcr_%$TRU2j$?VyyFBksJaJPNB|H-Hbh_2j2;_}tJ5-d5bJqWzanR$YtKf8k)B>8MxS1Hf<5{Ak9bPe)}s@AzujL$3{O=*SIU z)o}n$V#)9}LGC>cW($_pr7k8w{jf*Laj7Bb*)5yX&CV0pp=NLV@q6zc4p#~fbwlMB zy>H-@({)G6w=EP_anlQ**<=Q;b)cPEagOcwv0|Iy_^@QBa*cxpzQ3MCZ>O z8>f(MppJXrmXI$dtkKs!|JI+zmtW<>jxRtRpQGN@qRT12aZ>)xqI_+A$}JV*vAK@g@ZKC!&u%!2It%s76Wun>TuV+_RE+5{gv12*#w{70o?ogG>%t=9JBTzacGdU*|IwH z{@&En%b!R&&TQTCT+D=Mj83nb9ZH@ReC=IJUQ?|rei9DWmxFEP?$jHax6&`N_HTPM`^99m_H!@IJGz${XiQv!aL`&0fp? zxfdg_1~>4e1sY=Nx)b!r3hA9EOUQ7o6rmEIEUm!lpY7mTg&Z8~i{dX{}cPV*xm8V_SZ3{n)cEeK6LhE}1p&lOq`d$C|cf2EB0Q~w? z|LGH+74S~;_t~1qIOB=L|HFr$4_+va^l_MFd68IU#`grka~hsOb(mcG0b@idO{)&it&n_WxWT*3>eI^8P#;9IAX*Tz z>>(oF@o3pyS0EtZi{O0DM+s?%a5AkFp%Pb?(D`)Nbnro(P$jj+&QrI+^tauzI75~1 zSxzl)4jqll1@cqxCx*(20RpJ}Meip#Be|CozVBZ(oF#L^#xjRx5&3Vdb9c?jq&KI7 z*zm=W@g(Sy7OOY3>ir+=J8$xv!#jp7Q}X|gHII+;?3rmdz?F#%U% z58M$K zVd~dRgF$a+FYWs-jv?7(u32=S%M#Thnc^ccYfR>Y_hcl-1YMi*RT;3zQHyi!rrvF$L)g{x1A!~_zNca}a?K^a ztop*h_x&RE0}M|d)t2mDn(g4byBmkKfg=dcXYZMuX^}j_pV-jVm$@OV)jWoWm~S`I~h>p98shdAeX<1@>D z1_FiWcKl;|iQgV9A;spfc>SK&b?}!z>36wmZ?zsTWTiIGeXiTShwoiL;kzEtdN+9A z9}x#x4t|fz8!H?fhg{~VsltG7nmQ-9mB8QEAS>NB7$Gt=&SxgQGRZMO(l}UNEdF#7 z>us0PuF31GnKB2Gy0|1y3%uU;TmM)#O;8wwZ!41-&+hr3`6kUzv8NM?2vh(3x9T6) z-&8;)ZzC_mO~#e!rgv8foE9%)9K9Qp|4m0iY{OCbeWDY9vXgBIf8umCVa~Dgd4Q?k zpUFp;(+-Ea4h!=-%Zj%<+aW}>8x8##y2Zw_bP%llH|LW@hQ(`#F0cS!ey z8Kk(nso8G2@<&YBm8JD=(J zX#**J#CMFnC|`Pyo4Vt)s~pO{&-{i~nNeny>N`sE<)h{E0xl z2aB7q>9#H>kMw*FYePs20`u7@!;{!xK81}%w14Y8lD%u480>h#A?RRv`c23y)M?ma z_1`%C^sY5G#oHe_lYrdOY!<>anQZ`BK&HQx<1X?j+->EQ^oht<7%_MUNS4)Idp#Sz zSI@ZK8txoD)pd;D^}+LN;q3FnAM`gqjVG3ubdgai7h#=1MTvRC;>BLSUJixJq1nWr zErojwu~`uFBybd)sAd1MNY1921+W69o)VwHbTriZE(~P8p|^EZHo-&#n3|f(8?#ZI z4<`*mc?V)OeWZ6=ITiAH<23y`D_2YJ zz31SMd8_R+XGV1AhM)!4$z8B5oF9SKxdZ77@)O37dEYScvra-W_xyw6)IW zu6^b%4RniHIdD|6*Pa1Z0R{TjlqkHW>XNF-qlh!(GIbOg>}z#~JIflwEgp!i&T!#G zM7UJw)dZD0f@MrRQJ)9(Gjo%`_J9f@Ys(0gX?o4EH* zybu^-963L@bFw;d*GVVOGx0XdgCU+>TB^E%)8v-rOdr@#6CR2%NB z*X;a4Q>MR@10V5^pR2iNn*QFB<|CeN6|+9~BA%b<;ua^(ckNIt$AyW(>*z;&DeofO z-u8NKbN<%5w0edcJe(8V`Au*gBF&f4+HLOZMSm5MVS|R>8_r~^vR75traxq|&ijDN zocfPhy{(B}9DM!|Bz%eXIo2(2w6*?Q@P$D+O$|tDZ+c^=b8c7IR>+ih{}2*0$5ZpC zOmhulCHd;W7abvY;h_bm+eQ@m^#}P4wkUGe#^4g+3#dtjQ>-}_pFE*ilgq3t6qo`) zu=5k|cb>^d)q1{ebr|aP%QOw!Vc3SlIvw>buH4VUne$F~R3)}&x$j;J;MPzRa`z{4 zD}TEJcMDMS zcZOL#9HP}b=N^0fIwbFi^*Vst}+Y)fRySrf}M1oEoueSo-juNQ`e1|31ggGb&y zjwTyXqfF!pyH#~AEd

    CN?SbL zCI3McdMq*_H~=Kvkx5P*QaWuis#y_u4HF{OG9~NYy$67CY&iW*tYJVJc#T?9cjl^Z zFf+bwx{=wE)`COTEdm3|yyq6)Wg8nql;os5xeXecYw^BJIN2}WhgnsIGpOaZ`QFY1^?^C;#s+GF$5Y2=YFADH{Et>Yc_&VWW>(wR|`vUHS1_XZC~$G zEim~DKACldk|Gv4{kqdxnM?Ci3=^}byrsweu@d}h_$-!fhYdf*O&#UYf}^!#!37za zox@9PgtwDpDo2W#-W=B` zy`crQW^w>-B!RoW-x#`U#~Ld@ZcQDn4xICNeho_2 zBQo8=6*GM-@nyRygH~!_LDqSkYxHPH;xcC?>gMUKWPPL}Q7_a(g16h>)x+n#6jj1P z0Nwwi(L8e(bDk^;0TI&oe6y~{)%4#Fma4#T!S@kZPYL;gW$G<64w$T6HX?5Ww~EJ6 zMH{strkXb#Q+`vlX|+RD&ZiGfc*{p(v_})1;}|p0cH3=}$p6#sGd8*p$GERg?kY0w zndbkS`~89YJ@uwDe-(EuJ0hiKwPgptQQePn+}tnt-(bFlbZvxRSvqkqdz<2L?`}0w zUW9DuP`USB)#MYF(TMwC@#vxaR`qHl_dbfR-mgE>;i(86ZGUDGJhb{ZEN<<*VU-62 zveOp-{vd6>Vz80#ZfWMl!wkzl^d2&(V{&cldR!@6Y{VU!Q0~}jaa~}mzwea!3dP=N z^ZnhVEy`?f|HbU!a_?ov!}xF(|62+C=>;$CbkTm`CMVd%gRM z`33w>!m}N!{TK(eS3o(&s6EO(!fWA>^&|MY41VXoyR})!rR(JBdyRMMVd2-07XPpg)8SAt|8Us-0vGNVVcxs;fxXFD=h-DQFxt#PImD3b z4y!6D?%ifwZhXA{Bk61P_JG*gM8T_eCOBj7JegI@Fjc`%nr&)z$?N)OwKNA9sQ%o2 zB+i>+aM6&0IVQ$&$oTHryKFoAt22%fH{t4?X=W)GY47b~+V$WN-ekrZn{dqXKNCIH zzL#X0-QHE?GzH1Bd~w zdPh9;9s>M>qPmCZc45%Z&rbd52my!Kmq55vYD25VU@*$jmCf75>-s5HDpb?XkA{yZ#CN0re~5FTd5kYIJE#P9~GP-78u`$eAqI zQb$3MM@ut{;iJ9|rE0n$zz0Inf)?;p?+9KmtNIUO$k)ADHhgTiY1NtK_HE_Lo4m5= zF%FHvDbT=*a2H#J&cis8R0CW-L*#PIucURMQ9EDOq!W4ntm`?BPB#n1?)W2vz4PQw zqA|HHjGWu>z=Y~Y#v|tqE$e;QzAY2`om#$Puub1hSv;4&e%40Tve=9g9YascXKSFl zG#7Ww_fjryIQ!{^4aeQ(x$x8b*=+t|)q6?S?DhO>_Dkk!X?l+aUd6w@dqT&T_kivG z>=65R5K4SMIZ)Ml^VDPnSSF8sqIT3za3{GR6o19l>d!v0k7zMB;<<)|d~kabj57zK zeK+k z!>RmgkanQ<17#_l?$6w1&5N(5wa<8(Y*(txWwuA%yA{3qH7YKPK(+8bWA(``eakgG z8Ra5own(d=iYML;!F^K*&Esa{b%{pQUGUc;$$fBp?+|qbTUG!|J?OIHf7U(X&i0py zy?^PB4N`z2_w$J+LZ(%es|6zxRXYF9wIcFR#==^fmfTycZdaKDW!&ziVzIK|gDIv8sL zDD0B&zw%eQAFjK{`ZX22j5kgXTnU0=9}!QO#cqd=DE)D#01rSr&x;42t|Se~zHcb< z*tvLIP*`&N_z9ue;j?!%6u#Gf=p_9J*Ti9QU9Wn_C^_~tA&|$=U;X{O&-?rRZ~pr~ zg)i&xy!aXLI_tsTC|8r0J0}(p{2SrxgO8x1U7z&pVN!^iE{{d}J#;L;I1K@K4 zfI>a;J)2)1%BhxhW>SL$1T z2SX7?5uSXv?6bIejir|VFijrGay!bJVJ|E@b`#9^$KSFC@0Ww_zW>HImRPyTxOzWo z_-eA>;lhWcCUM;J>ireMtAccct_P1x-si>Z(}joipClvHsq;sP*W@paobKv~#$5Gn z!aN@lKdxG}4vl&)Pw!gyZ;ByDdPfllh~7chmyiFChR%W@R|tTycff}fmrDkT?zIm^ zorQ`%x+R8^?9a6P3ryKOPqJI0e+*7ci zy6OFDx-+5f!X!YT)$d~4uX28P!STW@0heycpxnl~`EG-W=5#XMp56u$DKcUmvafL_&OMuIb_1KAJb+q!g>#9d3%r zA_8L!okpADTyk9EdM80ZbgP(>;wBm~{&F5WjCQE#t$R|aSI#@GMAmv$qpX$}0D?upsE#mE2>>uOMiE{Qk1>%zTz4+qOljM-By`Sjx z{ZX2@Lr4~i zJsBciqP|T6M@e!&7*gbyaD>-m9D8Nni>&i%nyU7?smb=a^$?8#vJ6t!~UnAdpYE}jti|nXC1hn4!aMBz_R9aYVg==rc2}YvgvH#3nB9PED zcvTReCC~2Bc{O@2@mUvzm|HcTmK9H`0h&Av*7hv8p-9VPM3g+82zO1}RAp>%xjcx& zFdHO#;G~nQ@@-UxrAOiorYYSbXMxv!zoXm#d3OZ(;C_kw2JWm&JHIMwtP<2am6kFz zy-|3#Xevuuy7gAvwL&PXp=XsWxvv=&HXF0lTmf)r#KUNLRfC)UQ3oT@HmU6Z+$MWQ zy|+HliV5%chQ|Hl>Kd0iY2C??v-dzV3VIgvL$|DTM^nG=^9oz^-ebY8iESOGW1!T# zAecNrtcbvZhfSsNqn5@u7u0mf9dhC~^y?_J>c)pQ|J8dDqIvB6V|CpRBICuQF4alX1PypI{Z5``s)rzb~Z7=5y(e1Tv$I3xs z7%}YH%a=GoKyIZ9**J);b+7$!XSD3`QRd@{BiPAl81;9M{J8~vOO&W`NSy!vW9%GK zb@V^#YCAjLMMSqmOIs1)YwsiVd-aLtV70pYdvGKwJwZeb2@%1qXph7;3#|HO0vK|j z=0oZoQJ8+pf4vAml=fK=@igMd1;-AWw#-DqXFt3tre2DDvdi%Oy5642zXN2c+cXT@ zhPjIM{NkJHV#SP*K0Ne|9=v>p<%q%J7Iu}rX+pLjS|FMWQH$eC`VQOud+%Ap#6Z&q{3lc9i+iUhr?rO?qHXyS4SYY61skksR4xs^EU*5KI{=$$LWulK1ChdbRYX+VS>nHSQZr0IX^g>dAjPuparhA8`WW?lIBofABzV)Y z6P$v2+bzHN9z!D7$Zh#*4}IHpQ?O$oS}WZD$uh&E*~mu7OzHMt)hwF@ z?u!dOeLx8<5ws{SV*LeosT0h7xPo8*78KI6N>h-N%(ZD`+;j;?y}`D8ibQ)bYh;0v zahwene0F8%qnK3gPgty$P^xfpIvv{BoksbQC+~g^iH191m2@lmX$~`7KlgvaeNXOt zbH5MnYwow<;~Kg5%)Ptv%7~3X%pmUjuc$>bvdKg@aMvw;Tqi}OF=GyWTnP2-gPTIl z8{9UJK@o!LL;rR1_4@H7?M>Xj&i`_&bT8;=SV9!=2uE@=P3-hQAkzDq3;J^JpL!>k z7JZ+4-?;8d-yQaWNxerfXWkn<@A1NL(i`sGUi}Ch7UfRgcYx`SIdEek6Je2}jNG)A zx3OwQqCvFO=^BOot%pt18dfW!(bq@Ac`n>l4 z`&0P85a7pI&w5>FtsNUz`5^t-xw-f~9yfztUqzU6<&(upZ<=;q2x&M2J~ugxd|d|~ zwc&$%;&Z*6{}4*XQ*%A<_s7XY<2P?YqVs*t!4ANRX-1qo={j1h^yw9lw4%c&%5Cna7NOuoBlQHbw6kb{9MGcJa^K zAK<1wA&|^j2BjEq@@#@Sd;I;^3bhQJWxs~t-6`y=BoMkdkJr?li{9v1hF;eYeG zG`7`M^ski+{-@&ldEukl*Ae&o{ye_RY#5dUu4!@_*5z>hQ0sujTx~~<0r0&hZA%&F zXPfqtCf$`aeKOfa<%ae8`A$x^S$`77KAgW$(;HOvI!9nFciADZ1hYa?X!q&%hV?33aV*9cwzzYfghIOp? zwwXpDYu~;2Z0Pa?Bgerikqz%1|0X?qTqz>2{scT2Dd?wd*yumZfvYvcPKy57L*vx+ z+JDQFi+WOUYMY*!sv1xWo&Gz=6PQu)y>G|E_c`(`o}Gd2_P(0Lv5ua*Nfw{hPXV`MI6<&ukIk73Z5B!PeJyLT0Dr}_)-V!Fq*!7IO>U81jt z&yEP}+hR#99+oOo9jVE-Zs2{wT_Yki3ZLW3hZG)0Se;=XV>(q9R+cd!7aO-Xg9piB$(wJWM6lYI#1tpSgZo_{r|W0ojCgqNmtNYYE_> z#~Xf~%i-;a1any~p!lf9v8R#9l9vp5)Z?B?l67=Jh)Un`@cWas*^)q&*W_~t*?MrA zcje=334E3A)>n=SWrCr&rkS?9Nb_-tF z4f%=5{^u-Cot*gTsCD)BNst!rDCnUVvJa^fVh~P);P;_hkzkNkvFSU&$FR^e%Tf2261pZP11 zL{fyi)be^?NqBIAP5R!WVqC0WLDK11sOTM|*c<6#fBBF=RD}1)DfbONDq{?rvw&k0 z&N9Sz+>Cm8vD91ex@VXa)JyM6tKaB$%(duC5JOA>Rr`5>C$dlnJ{^w4G~xo0DYkAO z_uMXECKT8xdV*fvJs{}si;=eXsi;aDId1RUS@Z4Xw1#@G! z5?q%F&L!{WJo-cAsa`tKZ5~XH=C7uZ<0NAhJT5Ueh3r_|9WCD`LdodgKqP>qgY`)I zX14c~(fE@xE`L6mpY_3l2~ljga-!4?j0(byM~OlDm-qx+uEHsaPQ;Cay_DT zr|_@#MlW%PHYO3YIlfeNM7Rw`cZX(2!z+m#`D%?&H5u+A>FTb`VJprp#lN7*KYwP% zHhhZSr!`zoInUn1x?_jP|Bg2&#yLS>oC1l|J)88L^mWkYAL>iJt47tyRIdTq<+hKf z;0}QNGGQx{fOu<5t|i6uy4Ya=y*%@URv7c{Gx;ZttuyYBoVtf6c=DOzruueYp?47D zWRoIIWn9q=OQFP1pLeZoQdrp2-+uEs0=&Q9KYtJR@~8hHxb5?-6x+47dX>@du)8D$ zf|t8_`I|32`8SIOsdajGT5~LZqTz77xQ52XwcAvh3+;Dr9~{Sv_y^AZpZye@KNe}m z0^92fk0x4AeiwpVX|*MWq#eMWUW!NpcaCg#7Q2=_OQG!RVlM;e_~B)_Z>PZTi0x3x&^))y6y7X}GFD+u1ty7fmqP^2Z(Ja?$?p3c14 zNQ3ny)NJR^MXA3$Tq@P9)g>e$#Cp8RgRLviY!=}F3Qe6u+|SB^zeX32Smu8H$YTNb z!(WX(3gfA-$8iS-x;G?CnF|%516$^tD8T~b9Fxelac&+6t#BSByC8ppfHZiRAMyGuf;PK`YdymkEHr<)-> zd1&nWmla8t-u2#dc}RtyjN~5(n4Q)(6=_{CyN*1s3M*gQ40nnhpv%N zNpuK@Wwjz3P~9p;^L*!J-h+^xR( zE=h<8eJy#86yMLqUIysLSH7hcV&>tJDAl8}^GZ9EQ^Q}UuHIICw=a7aAsg(H{?cSH z9vT(6TH92nmE`7l5y&o{e>2>Q_+GURUq!{}QZirq;tHQ6)8B4g{O0II5za&I-|;K` zvz^IPrY^Ye5=hAAqZkXcI!3Oz{~;c4;=Ak7w#g4Ca(}4E@OV}s!Fo1X_~JUL$>x3y9)ggI&B z)Kqk=Q0Qd^l{;3Pc>J>*GIDbG#DPwDS`YU&!FtH%*s+=mUI8i{k9^&pGkpI+cWlFZ zcCU3mG?Duy?q_v<>GeA{aECHp%hyM}Un%y;eNWQ(DTZY3F0HlYFZTirI}J0InGvhB z*=wu2VwK#jmHj6&?YUn=V$qd`=eX&q^#+3R5^&n>M3dd=^K`=!z=iqlCBPoobMEOV zzukq_|Y*b#I9hyLC@|-@QGRo*-0Zpq`L0e=;yv=_=pAIa_mby+z)IAs4CnQEeP8{)pL727 zDH(p6ev7Xodhog`wiX%exI{R1^DixBqQ$p~!oB_T8YcS7VOyRLSAy*WCu-_dZ;YY8 zZS95Z)n>i|f;a6s;WjMWlFbojx;a!=fu{dT#U(nITi@3Z3H!bR-U8pq^PZy3J@HDD zM!=45a@^<{`KG1S%VV%(tv^P$Gge;q+>|eQc`SbhxV6xb?Y(C)5kgxKJ?X)5;34j- zN@gmX!;{^0x!mxi9CxTIX$);$xdm+b`!V85-O1#KVZ-B|m)NHF1U;U-QMJuq-qvC$ z&X4P@M>VcRUMh%c;q~I`@$g`rPsBSudF%aDj!*QZ_i1Sf9aNqBl%)LD6APKhmpak# z*yw3NR4w%QUKlfIy=i4F_|^TBQgt3J{;Gtd;Suq~PLV+f3!T7vd&>M%?}`wnT25Zr zmjIW$y`7t}QhvLOt;poD-WJnBY>y=kJtjs&-ml;)VnB}bVx%b1-=|sZ5 zZ-7eacb$v(MQxs!Phq|E9yzY#P4D8I+gPFk^oRT&h_dGvGIgWsY# zuHN*N#xSZ|Yowg4y6FuA-AyP6L(%)2S?mjmCTomc8>}(1yC*-wy{S*Rp2nM$@`Bu* zejWLNyYvHh(Y3Z%?4-V*a^p-sCWaEhOTcD;{CN6&tAhnj60NoMQmvu6b0p?+TRov= z9^4r3E~IKUQKMmBUU|8(4&pHjAWzFom!w>s51hTsyhCcu63dwXLHFj>z1CgZV*ECX z5AHSh14z5%z@5@r+>hw)i#r50;(c-tqxNiBhX$>{9c+Tx-dp#Sb3gyDnrAEiM93;w zop3pSiTk8Ya(o2#7cBKFNs$y|cv!WycL$*@120)W!`^MAd$f8`7!>rx-j`+Y^WKBR zivC5|*Q$xK+3$8hk{-^R+uzqdA5Zl@Qs>^DB=x?^n)7J!aKWov zUWU-kb8}O@^}(0_1Ll{hYjBBW0B5lGS#!0uK|mW)yB+GP=A!E8S%jqjLOU{inCPYV zUMb+>jHBj8FX|ja4p`1^jhcpIyysmxk5bf04Nb2O-`~4}$>9x9hNq0m{AiHp(Z6hol zpQJxdQTvh1@Ebrc-cD2X-Da@+RDhyBGv1}Unr#jHVz#$u4`Nw|?`DAeI>@~Cem`!i z`4;ERuU7*uQg^z9=C)#PNO1(3FEE=&JVvb#$-w(lsllI(G>&x-d8aVATP)6|YIkqE z+&f6lkA=#pv;84TvoB^D<#E|KZf?Dg6mR_b7q>RyNrV{3DAVR#T3lS< zg-b4>ElExQXz)+IJbGU%dB$P@u77=;HAj{&bgRTC?D_Ri0+XJ4dS^adpZ@4QS#qU< z|I&Ljca}OA8;%^y%G5)ObJ&y)K_7*ANN)_sEd$T1k`Dd6VBm}1k9otSo@G1Rv%QQT z{{eS5?=NGj+li0`@lT{lh)6r@hY}x2frZS?Le%I+FJL*eqFE&*X9;Upc(4(uCxDHJ zT`U-YLhsFa-aE-`w`91(-P}Xvpp+Ws0gY_YegX5QKxBn5y;yU0lH-N@%2KlcMS371 z>SObW4pSsQ^a>HeA41zk+J~k6qOhSwIiFNJCbaGBy@SMxej=P{)kHS?tF0y^y*O^} zcwPIXs@=QQ`C((#JEgcE0Eq6EQp{-aaKVd&1}nV>vGft_zxxY%^;0EpECaZ~{^Q_r zwe?--7KxA0)*Le#&%Fm4=;@t(xIW$IQzTiID+&Hb?_9E(abCo0to%iPDTc`mxl+Cle^z!@KT@~*j?(b=wa|RGm^vWc>b}N z$;F^3F9g5Ps~^bXKtlFN-Uh@d>9qFP-rNRYf+^+H;CAoB1-k#hUG|B)ObQ{i_>+Gz zYDG*xUH-93_ov-n z)9&WTdDuYk{BVAWP7Uk2M zGWQGI35e0ubH%-O*#t=QsT_y}#PGDh!ldh|Yzy*+fo2jB_qP9jkW6@pK}?lR9LD>O ze41|#z3X%M`&7wHrdl4uP}vyh6G!N>v1Hashv@@y?p*=tm|=q>T1FI^?RV_d?-0kn z9a=hgb(2_epR&i^3F>X%1(@&q!^yp?C?*egeC*HOXAWIs-3X0I?r`%H%9LdXR&wk_ ztG`xPS2)A*cFOh&hUh%Q=pLrmdEHv__j|tQAOF;8j#KMeoo5Zd1xjwOtv$l#BzgKV zp6m&r(OTG~WZ4YmES!tTanTdSzz&xj_3X9Ywe$0Czv|2QTdU_>&h)HFyTdZteg#Fx zCDqIjGD*PKLmNc0B8ko}a5W_yGaZO%_4VF1E5E!X<;S0yk;_2&O$TC**Z$*UFCckha|Tn-@0rI ze9|5KH(2f6Cj1G!lKAthzN95(m^{>$FJ;ZJM?M@LEhW*L6hhmQ2OS&(W zxl_7#D&<&#C1CDVmM^5b%7dGZhwIS0H9LbK8;Psmzm|z*&!G3_*z39-CRev($C2OH zL-3PjJUM{V;iH+;+4RG^h9G}x=z!9IC^2sL?ZPu@5HQ(mibQ5zHebb})MY*j3M%S$ ztZ7?Y_?a`V_r?d@JNX}5_ItJ_&q>=L+h)$S(WDi6+0tU{-`*D*MFTtO9afYd75iBd z?cGS8v&`J9vz%pj!=3l9|I?EJl8M8&a1Q{2&QmL06k zvDbCKK=J`PvbOgq?L)!~*mU^N%uJ`R-g>@f8VqxLAK#ffG9-L7TzUAz^lhKqC8|%p zje>;w`GG&sy@cGLpz7y+t*!Cmj_3ACD+I!U=rXs)rvLrCdJLfCzN@0hSKcn}rPKe$D1sRDKBUwa zc%9_lHHi&Q_l_B5D(vs4x63|~%0YZHL+HKvGu`h(KC^c%!^FJp-mi<^5eD%Lz9{HN{Z6I_m}XpXz~a%J{fUYauu zbC=CYmUE2wO#17O1Wxtz@97s|G<=d`@qD1u-&e}{MUY!H?zkPcy^se)Td%)$)>^sx zHIzH;XHAh}{LE!Z!g1nX9E;W=7*D93tef!eME_)A@8!QepSk)8L&_-i%KOFBrwL8H zQ{Hqjoak-beEob$Gpj9<741(0g!rN2|G8*w$~#N%&T?Cbmi!SyVf~igNsz`4v+4O7 z`dy2Co`PLc93ArtncmL()cbJl7Uh!X!}TaK>h2w8o;Vcjha=yXTz|r!kunzzoH?MW z-aQ(AdnUi5S=O~K)Ae;dEbCB$bZh0`ayLVNL>1hpy8r=C^bpX_5l0dvVx9*w-5yMU9>!UxV=9U(9uJ-=X=U; zW%+f?98#Pp6!Oyswts-qUqF6eBhWuhVh^;f_O_V^NE!AcQYmraztwpd!xp@0B z;?UZ(-1gJ(&iYR$Wba=X%rEPzt=}2qmMpJt_`2f|f}WWB=%?RDpzh>9iEuVS8m5Ey zhMB(n31Th7{(=;IoTZN5AuPq>#_yzlxawbe&zSYdYX2Ga-71&fGsq3iG2L{gevj-{ zutSQoc;=zpIbaEIfVo?^^BEg+Ozv`*nddi&7*pN1;PUpqpqx!;csRCVZAvuANvoro7Jbli-jgE#YY)p*e@j{stX4 zW}YnWKJ1zDq7y&nbGM8&FmRMMFvnppm5W04Im&O!^2>{}>TMK3Y<>%ANU2Yt3G)!# zn#2a@4evj4bR+Xmr^_xSzAe7PgX60}3W{~!zl=DvHY~T9IeyLm3}da{A$0HHk5QI> z&k|1EUFhzwaVouW)*rTZDDLXF(|f1lmE=yOuR0!J#PN%tE@`&fAZ@)zlwYyy!9S+a zQ`6o%TW)jR{GAY|{yx2vppCIj&+nn%wb;)^umk9kj-s^NS#qCv-?sO}QsC~eVL&1RWM0cd*|RUcEN_q6}?M_xgDZEW~JX`?DE=07*;|}oSm%31002# zlGQBJ5wktU9Ojb|FP%sceGXLq9w=>v@Y=uTF7xB5v6z_`v@gx7xm4B;x>VEh!^+v5 zcOKAGW)!82V9o`^rh7t=JxTT{)q1w2M>i273YG2 z8b}d;`nb^d-*X2Y(q7!nk?h>vk@}oGauY45+_~N-?yLE0s9$j}2xGQ* zdyBA=!Gy*1h)MNq%-SQ9qW=ulm|ItuDI6Fog#d!F_V>kiPv0>|z7sCJ%J(IeP(+e z`vgv*{VU56{L1U8dR`8G`bQ%5&KYf9cMm{Xm*hafyoc=!zEMf6{(8TYj#0^=x4$dajFKnEJhj?`REH z<_`1TT8ew(@_btU?PD(dnF5~nmITnaXz%HEF`I?t<{c{UwO^fM7BA&H)x9YnDpYNjCyIUqpC?~KL+Sf~*_vWUE zYxYBM!OMSl2OxO3(cW5b6@MnRGbw&!zXv!Pe(9Z=?Ztna+1Qs-CJ0(%R&e10SXbB!c-MwaZeI2{Dl#-n};CvGZ>dA@eZ*=(biVUr6!Olr1i!vO$ z9^mrW8z29w_NA=7-kk`VSX0+G9wd^k`p~!gx(7xa!L8U4(dhTc>Zk7e&IQ8(Hsv(l z9lkE|m*dy|;?7a;!;{~l>7XqsRPoir8Lj;*#Vr!yyo3VG-p}bJ1ON!PKD{q^sPnsB zcj=vgrB}!!ychdDz_{By!F)@GMVBL@=|HGexv7mjd zXuUYxC=cNNXi>fK#!qLc$1!bfp-&b&L^Ah7FnY(l^y6jYWzvn}t$b+7oGSK*#A)*7Ri6vf}i7$7sOx zAQLteMUpPB8aHF><-SW+JLz3aOp3#Pb5SI;@r;i1Q$a!lAdTfF`QeAnh%`4N>AON> zs@&3B6!P^n#9-N|L;FHNqpQhyLt1Ou% z{d(PY8*e%2uOUsoaOcU!S!{t*X#bIg29VLdU8?tbS4H^{Y zye ztCG8-mYJ3CQBiv>cIL@bvqEc|J1CmFmGhJ6ej50`Ai2-;+YOV`4Bg1*@`a8F*TAr| z_YVEMzrPo+u*>su$&52-C@oH1lLYHSbKaj49f5o-;u(!_-I+~615&WiOe+P>S9jzL zwR-pL^r@0n@7kn<#+)o8cm8n=ksq_=VDBn#S~X-sef`yYD5xugtvT=w%Dr;mvG<_D z56R$E(G~}a`@!sa+ejGpCu3>_>kOVOaIDjckmcaOdDtt6k~4@zBsNw5y_BSm9LuA zkp(yr(HE`LJ)1XYy+m+^fmZ~vmh;;V%d{MZr8sN+QGfIV?qJEO%KMvQXJ|?h4*lQU3eL503#m4WVk#j$U4YBEBCLIJArnS;0x&;Y%$zJiC2T0HnYw? z-FAHRJuP0HbcU~Mxea>LjBF2ERJ@}vb48clv`x8+v3 z6IvCXrwVk^`uumAjNUU){RZoy%j2{)@??wxpX)7>+iotRzLV1mbCxw(>@&|M&5y}@gTWgZIT`Z1iC_CjA%{M%7)&3Pk_47pYL_F@ttNt=hgW}L9vl)M8DE3621 z_g6I>%}%?L8w1<%jFrHeB$^GsT0`Wv8i!-H3$Il}CX{+-10mm`m1VG9jFdZ=t(*lU z7F{=jy1k#9N{Un`Zw!6-L~sgwD5AQl=J+8+Xz&}IiEddi;XZ#^k0 zwnr34!>{6K`mtQ6i5KeZA!6ENEv4|UsSgjjS>N%1gCfE^0AN6$zggkJ7qil^;J7NnC|v1lF_HwrTXWv85?uq`(EYu( zm@iQ}~4zKU)vd8gV#5!FpKqmXsm6mXX_ zRU+iA4_LuQPL@`JLT%v*Fb$usDddg0h|%1qvo5owApB)re~Y57>90df;Q1lJG$bi3 zKA^Z=8%nc0rUEy;LkOz#3L6-%W{$&@>uG^VN}7)BtZ9-n#|A>lol{s?yY|7s_1%f9 zsNT-w$Ubow|B1VpK5@*+>AoN7F+3QG?EgKQk_clK|5}E{Z|Y)@=b%h0V%z5B};!lyz$7E-c`%n6Kcchf6zVIAGlX`_Wg-_ z-SC6E;&BchI6t`G(n*hjmzDVvm}i{w(G{8RXb|cc{tMUcWY>C=HDx8cp&CfQ`SD z1Upr8DCRRq=pD!%gI`3bF#HMi#Pys8t0OBtyf``S&G!NnVpH$L+lDxz=BPI#hqX^U zy8TT^RqpE>W!Mx?Foi>l4+8n}-LN}1u%*sp?*RUOOPn7(8}rxuykF<@-~QMBk3Uf_YVv!HM)8ehY2xef-of>_*9`ku;_7|2UUf@)vNm_ibCz(Kdj^hakS3MM)6zao^s>+Iy@y z@aY{)Cc2#;uO-(WZ9Ftldxvv}me&TaR3@`iz#z5s4^V@iNApv#+Uw~iF^9_#<6DQ&Ypcly%K ze>&DbBw$T~q@A|mS5Xw+0Q4aM5+FWgVIR)@Mlrk8vwI&090Gr_$AqH3Dz!&OeL_7N ztZp`1?()u>uIBbI@thL3YZqQjTSxC2`+fwa9rx(A7bqXyo%_R5modEyvy67D#!=M! zJN^h~@Q)DN);!zDcbeJ^y%CaUf@X=~a_)hGj}!G9W^xW(yWKflzF8pp*-nn9l`g)u ze*OO7`^E7ht~0`D7dy0?E$$}w&Ulwbu{~~PeJX7%QXH}aTW-9Dy?f_@3jB}nPw!96bM9Yq&!q1>89943k;C^Uq2ldmxv7&cg>7V<(s+zU zfULUF3AiO{y)nOyWwy(B%oK7@ z$zpoF@uEq#-`tBEZsvO=tH!2CRsSe#3U#uZrIiCDq0Hx=5^gRT^iDY6#&VNM&^i2V zjHS2NtT#fjDKN^j3kbnySjdD?@zMnSD6q%=Z2qQBhdRJJ48!?hS$G}wE6;h(hcuaO zg}B9J&C73r_}ydYqDhW&^cpj^IRd=bq%c8!vsHTdc}^`P(a`y`DyK9j#$Abe)>|-7 zTGvLM^;|`$zW%x%3+E(Fx5{Z%HMSSF2=1x5J=E(%_l`V|f|(ZUm|^Qpx7lu#x58L_ zjJ0mup3I$y=PojP7?s*Y9`@y&^ar+OUcL2kZ=X@o+!5pd;NXXjOCs6pwH4b2U$nTH zPxj`c8rvf2XY?wC(mOwO+av>#!k(eVl+V2M5YrOl#Buz&i1>?Z_mKrYIej)&-k*d3 z9OzhN;;5AQ)VLzu@Va>k1-9RL0_r*IcSh%;cX@SNa|I>9OMMSz{6Ub1Gk%zgJ}yYY z)De+G+T;$?{=#XmdPNHhHhFJ6s{Ve_+Pm66omYnrSOcDz{Ru3@cYf>L>1_bMTg8ou zr$q~Od|b7F3igr8-)4NqmBmFW-FrP--Ok6lo#!YIzUgwy z{yOnE*Rh)ny@VB^@5$x)>moCk5QBX+Ek#TW=voLd6A2P?bYGukGVEwq*C85u!$j5F4L81v%$btCvL}B|Kc(v%UX}yL4+x@zF}(Pj#onK%^D9SZqs} z>59{3+(rjQH#AC$JAvZ8unI;ZxI0>{6mWAT{ZLNFjOK0Ac8YM2;2D~yHb&Fji)Y6E z-j)xNh2Jjg61e_%-N)3%ecs&!K$j2h`^}x7DVSfXU~I(ATKC06OeWV%M~@(fwk*KX z;r2W{9X#_+$_+7C6tEg}Iv0)Ykpq1gFCNNWraTKdtyHJUJPxw)?Hc^?wxLU6sI^}?J?fQ2HZQY+JTdQ=7qO{ z3|THEqLDum8b{OCRj|NgD}F=zv-gYtzb#P0b19OK2tb7fx4&ONq}{hW?Nl<5{xa|o z>)w9_p@$7zG}b`n*PZ^n&IecWeZMVWKcD{h|MZ{vFZ|O#|Jm8L`{z3Ty1(w<{Av8l z)Z@CbGnc&a^RE4>S33?~gBIj^(EfrC-(=B!xCxScbEg5rIaYbf=K-a4QihM3_}PLb zXFvFJimn&(f(QOAw7Qa_ain827Z9pH{TyZr9``NOa%$!Fjzhcc|qRK6i>W zj+*zLYJLrNQ$VaZ!oCWB`OMurAr%rHLGO!7M#m=#s=bwT_3g}#mqV`iZT{J|qOQS% zB}P04Z_~b>$~@u7T_^uI$t{7+p0Q3_`A_DX|8*n9m}J6q_%sm@bx(;eYHjDng~?x0 zt?L<7AUf*Vyyub2!gE_N;1n-9k2gMBrTm8QZsmEeaJ%oJyZby|1WG*JK2iAmOq}1H zp0-v8hG=4*-15A)dHbF&kO1-J_T7UX;khg z@2G3dwL{(Y_o*ZSxnM+jrL0G6|*zsCyd+%!3D)UvC|9a9_gGPydO0IR< z=vRsCz6S~Tk=AaxmYC@C@JIrsck~XuFBq6{*Px(_z1jTh#_?`1k5`)lA9^=>cbJ2# z=Jy#=$LSYY$s{}eA`x@i8XHsb7yA9+-66>#tgW!)qyC1m!&Jj%W5pE|@aUzr;|-ca z5HZ~OU4$5gMVhWJdYP)@_cNuxwA`8HF3QG zg?yKOeG@X46CU*d~xid~1|75$9 z?-Q?>4HbuluSe9+0yy5m^4c4l*{I}$RN{CBDnew^L+)<+yUq9!fIf;(6@M{Bg z$I)1ND`cnBF(7JJ$Z{pzx4~W!kC*;ug3Hf$IHG=6+V;iWER!Z}Z1q?>T2D!r>l*2@ zwI&bA#EcbRjgs2@~d{BV-Vw0oaB^NiciZ>Bx= zu9V+ruxa%!NB$)z9mqA~tp%Lxkg>C+M-^G*6!#(tMb#7y zq?wa7?xx1jr2b?=f1^P4pz1$dOI?gkPS`%VT=>3k?gz3XKg_@SvHLfPAFVWraJxJ* zHBo$2@Yvj5!S96iEo{pO$|+pCfi!y@A_z})mz%-=^*mnQKg8Nq-aidpZFYC-Pw&wo z_hHuQxLDc4Ii%Kwzaxe@Lt8RZ%=!#cmi*xG86a?N>1Fd8!mRy&bM48{ObLs z{9QK+^6a>mCE$wzuT=BZUOu!}?H{uA??F7jCwu1*c_3ujxz0MH-v2DG%Xn+u z=hFR1Bo*J{E3PvO{Q~)J+Nj;m>^W@9^tM#Hz(2V6XY7Aqw8YGR8C=MQi*Y z6|<{^kLDiY+@}fO(H^!o(Ym5HhS+MOf>GXDXk78$`#Hi7RT!fCQzOB|$3+@W)TP)e;rPDbe231g5z;Phg%(JUUzr4zPB(y~oMNX45G&D~P@4 z`aSa;`elk{DfV*b0A^r-Df6R&ha)c~UXuEN1L)=VQ3g-f24muI`?AJ!2hU0nJ_2Ab zjsprgA@G%3!aD8u6O1TMNa!C$wmkOh-VF~b_a25huD5scga+<*KinaQGG--X=wfId_0NGF`CR57?$>JfghuA^5NpKUTj-|htl>cOlY`o!7O6u z(Ahwc<)w#*@)m{S=)h`Q=$P0ZD~nNXesJ3_FHff3*LBL*V4J8{(DyAT9prnlRYbH= z24AkJ3+XOvj4#nWoBhd)>+ep}5ctY1VcqsyFrvWShC)U_SIc|vC-6}1y&tssLQp8w zIP`(c&9#W;5!jHcqbW4KM}X~3yTb|7^gWGCm-&a zc8Afo{hfC+e8{?6e`FJs*d@l2{soV}nXZk=(Qx#S*dp+ShSS*|;j4C2Vg>2vNb

    2HPU{ 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�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Ě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�lho1IDgQv|dm#`Bj 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 z zw7IbbN6cc!3J(Yq2mG3 zHlDpx;zGAiRH#)}JQn5%csS-Fu`jaWxBw!Mn#aqCqAC3)12RZ+)1h zV=~Wj-+{R%3*2#PC{vP#h0^{kdcvl#FRvZ0=hd46{v+>_2Q>dUNhj~BuK|+1IX#fQ zE34jxH_H!P{c283dgq?0__**1ou_A{FxPTjWuRmR!UgTCC3r^=JRpHD%oZcZ+%U$b zhRJl~Lf*(eO=;L>x!=*56YBSI$=)C2IUjFQ^YZoM6A;yS_-QXM!LgSd4oH`u{#kix za$0lEPTvsjPH~Wd)L%Gn_-DM$Qr~e_PK}J)8cSS%SDn~tL%qY~J_v5e#)$K$f(wY+ zedzL8UWIvR;d_z9eH!hrSuHM(a!c>U9HIfcve6>0+D)OT14#}`|P?XiMt8)EUaP} zFn}A#4^1JkowkIBV%5J(KOdm&5 zZ+;cei6_#qR(e~@=ZtiEKlTpX-ut#_$U44#Mlx_2r5Rp0qh2$um&c zu=!tWp{Q$UljAnoJ_tF*Tc2dOsJA+8^&VRJ52qtpGvb;hcX=K#S9e~m5`J12{X~=K zUn=gW()dQLd_Oew;UV0eVv&K=zi{60&nu3sXK}=X%XsqcAfRb?c+f1>`}oyZ_sFOX zakV69qCn_na!Q!s;+6MZYc9_(Dg0KuTz@GS_#yj??)5tdfyj>;9hvbA?4g@aRUT)R+U229iw z;aZ`do*^PfOrEFW&R9Q6X#E|yM2B86ko^RQyfPH9k6bc8*|6opCDfxfhuoDr&rW+# z!KUEGu(D7ODu};2w7JI|P6z{W24p77SsBY+ zoi0Or@Oum9gULIJJ9n4dAFPm6-IYOs&NgPTkiiHPhF{?Y5#On6Fl)J+S>e_+x>5MP zhr4y%-`(x=@BdGCbB^ip6?hH&=Ug?pxTfFIE1ckP5&naRcia@OzvgbCBk+5q>Nt6S zv)d7X%c@NcXum6Q$KYU{sC?Zx233!%K}nQgqP!ycl&dG9@sF5$ zKxTq0ot#3Si#jE^cTMq_A6|dO4O6z8x8T9`=khZ`M<$b;IB`VpppqK%9X4xbq3%9! z=z)@~BZj18?r85ra))q9gOv#sgb^QSHo@-Ky{Wf#T3Nxpv57F=qnZA+O0QvJ@3&!n z>ecrhiniS&w8u%tn%86MZNQ|1n+)1p-O|mZ(QckB(i|f425p__-=I~QEQ`r>GRu4N zYzcdQ2F^!P=L%{>=OW48xTn~y!hK7ovX+_2V)La>N1mSAk4RiTBm5SG&F!vOndtkv zuU{_EFa2U+3vzuy$zLrH;sX%BF7kerG3RLan}mOR9dBvUFN=3Ma%>geycg_!Y~2qU z5&AjW9;rZ%_TPT@`LauH)On=L`6_;K)?Z<-miwiw|I*w;gR&%)>f&){!=|$@qxAg+ z*>_xXw*-{mxidSqYLu%Fd2T#%F3u-lCn(}GDL*)Q=#vIxp7lUZ1@}8NQId*hT21fola4h@)alom zanalRr&gx*JB-oZnWe5W9~A91AJGUUfGJ_sXw*0M(7dYg#Zun|tcE?PR+|6Tld{<4 zIQ}7lV(b09U2Fd}uzemi=4xqlsC^LlqqK73vvSe*(rJTndnKD`a$}I4=G>N^-qV>^88TH^W=nq`zhDsk#SM zYh|PN{ixItiOQVgzF9eTMo?!<6Vdu<+WHW>b`FdMC~ASs)AexU@BT--K3HU;G4gZco!EeQbEMeDv@! z_+xDi<3aFC&QwRmz>7d?)FWJaUoXj@2KAa0xcZL?|GAJ35bgxW|==D&*m_22JX zukjy_`Om-pRsX2TRKMKKJ?kll8ZXU;%Wl6+dAyW64%#GuIQ8r)aX8|0-a7tl53aHxSXzAalN^r%{fKGz++r-wN;2-wJWHx!3m%%Eq2|_m0yR z3}c@4Ky>EPwfF6PXeC^<{x9G2Mzs6ja3F!B(<$VWrMPbG-}mym_*E+UpuevmXz#fI~cwT7y82{C#>Kr%nIu-sRy( zG}olMv^sRWdY6osH3tN)hYac+v>Ys_kyZ?bV@4l-03}9)@<>)wFwQv@@@IcU|h z+y@ev4DX;^h5@#UPUN!`Jy5{US46-p zz4{FrUv_eR5mv&!?ttWSFkBZJF4Nz1HuvAR?xK2sOhPyz@Mh#VW@CZVF_T2wbMUkN zGMRrl7M1MpT54Pgtu>#nbc2Fu-4o?Z&&IpgZ+BY_M~N+O{&IOiQPDP6xa)5DLAI*8 z-ypy98v(8949v|lFn|HOkNY={R__enrQEkTJ>2CTxDswke-Q2l1nA{zfV3=*KGm{w#&CN zQJeoM9(u+*jfhV&J52mHKbj&!%n3DFAE^Xo2&T@Ws5L>~U8aeYU?v=9SBb3e5u;}qQ>QaA(0K3Ihx>Xe z47~a0G#?yNXN0XU7U_AGgvRcd`T3EG{pP?dh4)guA{t;-tYgK zuN}j!3S5>ksR9O|Xcj)u88TRv-dDuJT`%`ueeaD47RTP1ZLw*UL%gLn+;r}J_BpK! zjxJcGNvi4LR%)K*e7V&?Ao2Jtk#KQk;$n6hmx74cn+*}Co?v^K?d}HLJcT_Zl62StOf-fQ5IFlm*RJ98+ zq3Z~icTf_T!xRDn&39M@>|w5#aVacHj(3QRC5ujQ2}Mm|fiKqhjV|YFm4S>m$(c?1 zgdg*9!%d}^!`I8^AWz*My-9R;e|)zyv&}DOW|4o)jEpkX`r5m@)6~bq*G+KvXyv2i z&L?db4}87qFE3DhT(~>xylJ{eRzC4#@rDL83#8EK`hK4r|M~v)&wt`yjX#?I{?~u>*#-SWfDh2*RnH%uPSz!ZF<(!oJ!#Fs zvlg9rZaXibpQb3M#wL~Z{LRDpgPDGk>UYS+KD0vn1h{N8C}^PlAQb z`S8xs^1s>UnmLCFkBu+ZRMSwcIfX^iJLsHZ?p?iuA99>ML}D-3a0?Bk)7S?4(A0pb zpVQT-*Xavk*uON=puKCJ|E=;p5w+FXF zc{j6sIMNRyk*D|6>4P-bA*o%q?DC)~#f|%=&+7Tq;ka~m9>kKDivWLs-N^j&Tkmv3 zbCJY=ucO>C@A`NO0EW16-kSJYcKQlarSk--sUBHhNk3@TAm9=v7MMaDd|Ms3J7MM_ z=$%rE{WSzU4<1tbnXxo84U)^M4_^GF#qUeMPoFH49o-_tsqOB4AN%F-b!%-p@r~ZW z^yrN_7rha;9s>}!mA?Ep7(<-PNKfyex&nuUrZ(R}46#p({T!SZg^(}?XjCDR=Sa*W zp}^d1YXIjk-f>+Dg5H@$<=o_X^7|&(nr^xpLuX`+qN79 z99wRNyRjCnh~^Xi|;$^CmVUmjiO= zyx2XB&{WWh{aKy4YVR+-+NX@xH1n zl5o|ee$QZrB#lo4yDJ{?T`OUB^oy|fs?dz`VgG#7-rs>rR7JTPo8R8=dlZxatWZLbNx?{v13o%iZ9 zW7EG>#ust9k1LxZ;(_6KoNzqov=0N0ckBfpltJ2ihHZa|!0Q6q<{H~$(;1L{;x0e| z*F+#s6Hi_QIi=P=QDM)Eb;0t52kSi6=IML&qh{wzJ{#Nu1r?+9H7~!nGr+4vLq;aE zB#QGg9*@c$%5{TlW&YW7DaG8lJIl{>vM~Ck9fx3rNrp!kHR>yr^78pa`iW!XACS^P zzdvF#rvUiCRB88=!><+1CwcMWy={(Ljy%Q2oeW@5Rl1|>oI|CLyx-R$ajC{-`Tu0U~xo5uhKvXuoR3MDs}%!un2&;+RRxe!I;(7PVLYJCjN+8_2Fn(FfL z*!C`J3~gguUl_9Su<=%T==ns>+hhbkzERe9wPg)DJm_rN_;`QirNH)LZ6a>$yvaF;JrRO+ zI6H-P{%bcb?wU)}Zy4aS6XhiEEU~TLCGKw8_%Pkfy974e4qwtM~)>k zQD5KF_%_a>d!&Wir8#?%i+|>Y16ySy9Xfn^W@m>Vx!fcAKBB6YPzhnvZXLzMtkb1G zO*8UlIzew)=ubDGY9npqcYW>lpAoO2H_4yq%gUd~1f$RfoIrg%2yV#*>u;7_1Q#2= z(;IF7MLyh-aXz;a{~yABrLSWt;=eO38hmyG|3>}jr8kchSuZbbIt}<)Fid}*DQ;t0=ku=2ha?VH#+qx9jVvNg0 zmH+-G4AAxYUwSWEdiP9$tINk@w|8|nJtTIpVbGMvuV1SirOgF2Vv`a40Oz*aak}~L z^E3RViATntFp3%x{}$g|C+_t&kj-=>*x%yiW1Pi* z)*)MYzeN_O<&w&}99p*udpPZGu1U^eY{Fo#O9-E&xPX?Kih5PgpH@G)gZUMiRd!FD zAD$`FZ_)b!_fQT$_nf@~*bZYtJb>xSK_b^pBzkA6?n4h~HsEdQk#xIva1hgh?9CyZ z8J$uwxKTY}n_7gN(v#jNP!gpEM@0I1A&ei4i1Pfb7o^ z$m9Td1>pY!?a-(dQE=5z#Rp*xr+u*DkzooRL2;Y<0zluNrd(hjO1E1UXpo5&gU`+e zeQY!CQpjSqMXI^L1{{Jtup$8Rjd@P*5%)v<;~bAIKSVhQrLiN}!?4_V28`0rNhhJ~ z(j4<1!L3v`cfS&l52Ck~yM+o1q)%b%9+`O@zVbt!@)Q1w#cHYylT@(a}G%f|J%}(^nCsDEb@47_7A&} zrENPUj^C#d+B-=q1y5*avB5xvfm#!mP2B3#wT4vA+OM47*A zPBqDg$KOsi&)BbVNVL20B-KjHS7^G8_vC;+33T-$7#<1Yx)P2YaptZEkXcclj*2;} z{fT#VQBI%x`R&Nm)0c?!>5a`vKJPCEx#7k6;F2isK#+3}BW^6Bt-pz6L(d0~OkW9j z)a#8N{{FY~{z827+FxJaXfMk16E;aI)brtnO7C-=SpOaW98w|umnfO;i*Lk6tXzfc z5t0!RJA@N--oLt8Os%Q6gu`ZtA&7`$d~}aK8eic=bN3~7Zi`dGG2jsgCCA7mSY41g z!Oeu4F^p!u3$muEkxP@<@ZFl_mRg4`)>q;1HKi<$z`gz+S?ea%EyZGKNsW3l>5Hz; zAKi5@sKa@92qMN^KtN{^)Wp%t6TM*A?-g>O!jZpB8=F@m274bpO#qi1v*$9-SCpL0 zwz!v0$C00N4>I3E=Y>;59OlXIfVlL2Zb>h$AKwG?2Odg2>UHSlhCYtl*AJ?+_1&QU zjr$87!`1Qd_eP$dmtZeG^eRS|#EXiSN)dm+Uaj}kR6R}a=lcp0v%XNCRc{|9bSJk7 zIwHTlFQ&T4r{el7TjN21Yc^bWnNeRMv-gd@e#;h%63~%LhJK^;IhoD$-Zv6R#uM(H zy%s+khA9U2&Kc~7Ea;u(M(=AveAhc02^bL}1qHZYo+t?KCDaS8F5*}u964}xJkgdN z;G6@eo*$g!$6dxF)^4 z_`)orlc>i-+2kDSdBuo*-i&Y|&D+cz?8SFcnn2$fpjoxQ6 z`P4gz76q)Ok%?mCr)`Em}Rq6Bqy8I5OYc0^_)ilmYLP-nHXU*I1v*`BHDa ztHDQ?gLbg+%Rk@!xLgJA)b~%$aH@lK-HKc2rJP4I-zkX<()Y+k=T4~h^HQFd(eEj{ zyWM85*N(sM{-4D4L28R$;+#c&TZZ+JYMwJhf+r&}tngnMNoW4dc(K~nz6GZG< zdi;+2l?mrYm~L!ipSK<+pi7=E*gIr1EHz*tm6b4bdV^744(5Xps_dO2{dn35%&qVn?jh*Mo3U&?9WM%iI?3Zw>Z1w z4JqT=l9u&kP3VuXVJE?hsY7zH_qfNUYK(NhFs<5(c7g|1vvp!-csj$`8Mw{}xM2|c zR_n&7bmSY2c~~xq%7CS3rrdphs_(MWRh=lA%%->x5}b}4^ttndLcbTM5RnZ~Z<}GP zJqEey#pTC$l>1@Q8lrgB`-!1ffzyU5@ZFl|Zxpq3WJ@`S==7dopiY2?750)ij{6N2 zB0eYq>N0vjca;GEc5?voDhRJj)F3*@f#^CN*45oX-$X*D>DGogQSV_>s%fzVevY6ie*Z9xq)eZ|;;MTfaVYR1U5p0{kX&yuKxnJo^F#dpo=2;mIDC3K_>pjU|`rjsRia z5Qt8QBRwz*7$c0UXNIzu=4B!3*=%(ApF2#innwDPKl%sr0ty0VcfMIGVbyLJB_fFZ zB7nYA%6C%{Gxlhqwp{1^@nAU2gxf=D(mm->HWfszu?N>Rf3&{g+g0Wv z{^`-sN_aoLw^6itBZF*svEkq5`_M}^?u8vmKynvcL&Li??JlQ%_RZ1n2oi6u6l}17q}-vIwZ2?}5DMu@)Kp=xn2AvKyXoivp)jN9I`Znnx9SFT_mZYXcu z`aZNB*g1%G)p9V8km;;Sy{}dI%Kf3HmmSg`q}@CJuvnKQ;&|y@A5Qs;l}_Z;-+%}; z9uw9g2uW@R0ohhB)v5K}L1g~ZDIl6RTAxn6!*W(z3rG05JnC%qKG8d#H?l{|5mWm5 zz>Sj)Kvei;uaBxGZY)mngV}6qqxTiMNSXeAI8EMspfp>q#$ra9-hEXn>RF6J$EID- z+tI+N23NGLM%V}eOeiew>jCdNbqppluh|ss+~awHHSvlEnU&qMEyWadiv3XcZu}|X zobX+S{*g~X=Ptv$p8l@84d=4Ew+6K=onl)s67yC1cF_nVZ9G|$=)2yBuDa7#XjYgi@HCqp>B zLru&r&?MuMg(g#ie@Iuu`e5S|5+6UMwLT92!3%6SH;Hf^37z@f3}@@x=}&SQZaikO zA2`fufqjsM5Mj1Yj!;JsKeAG72%h#_E4o>SANT_nqGEDo2L){?T@#7B!?22>(P2J-Smr<{$q5UVmOqt zk}i&DBqX^R1Y}#ymvSUy5r>v|onrL(GS@qVjish}RhZ`cNzH4xn$HDl&H5`ZA+z)C{6$`a6>Rofz|e ziQcu=@@evOY-1&?F&%7Tk7vCk{k&N>DpFP zTsP4zD}R*W^(it-I^YLnAI%7-r3LgZvv2fHXZ|#tE&pBYl)|w5>U}soiS5y7*>}Ro zY)1ti9e3|YuW{{PO}e9_@aA;&vhu)q64mt1(@txB)F_TUq#gn35DdA*qmIc~*jt7u zd3U4uG@In$@B^N9UGkuOZ2Rt55yguo+Ld>=udRln7r5*pXDC{%1jI0z zq7oSdVCVK>$*n-j*i|Ee-YNJwqr*7q35Fk6y=(+ zmblL6p+wLS=Md(S+nmdmi9V9x^84Z%5}J>IYwllpc1ZsD30fAUJ(8BX_)J`3eI(`O=056`X=wlOe|1Vgl*+LW zKvX|blOw^}di-+EJ-*{R743S=Nq?`vX*;i>7W0=-RzgUIoz!hD!(~B zJQjB3x{WSstb)Lz=GxVb2;Tk3-5BHVGIz_sFv*Ribu*g9E`XGP0*zAzV~;?=9Se9c zdsYnA-xd0XF7K(3x>b{i^I-|oooII8mo&<(KkE(d_SKPi4xlc2p3#E1QXB6!SHj-W zdpi7lbAfKp7iP(KOR%MoJS^?<@;;KV|a%b=il509n&~TOhsK?H(!>v!+s|}8S zwmi^vp%OFR>_FcUF7|t!0+~V++Ev={t`G@guL!w09d&s(9=^aLn%Czn8gJQJNz}`H}MjQkD6JW-2KGqoi9I| z&1-~*Dydh}GI8gKl^_dTk@+;^0Gx~SnP;gwo{zfvWXn13+~5eV{hxP##P;HsgD*Z` zMe%*T|Mrq2Kj-~9u;VXoP2^ANG){ib5A^xI0DiEWrrrFj!qSDmzb`PJH*pZ_e$;vc z<%_Q|-GO zma))-82`jxFX()~oUMKC70BJdd>rGi(*l94_S&(+z_>weU5XPGTSm?)bQ_^hOr9t) zNk!By91bN85iVlLf&*|6q%4_{P|FZZQWf|fCb>1DZ4@k~B27Lw|CGuaSoHOwn=kFN zCHafx;Ct!=&AS|1WsViycWbTbY=!d(a>5;tZMw0bnBz?)S=N_2T5RR2cU!sTp(%;c z;K+BkcT+^UtHbg2rP%Zy@oRDSBk3UZ8zhdMw+y02lV7UZ==7_aERMY|0YHHhz^0DM zeOriRvyqIu#*Tx&tT#gM1655Pksq_Zxa}j>v$mLIo(VV+-}-Ti_+dd*DZcbhHD9QP z_#0dPx3yO98p@`NPsz@55{m?!0yjq*XS(XYEgBgi4pN-$b4xk}B{MMS>ksAl(a-US zoHmL>U0z+XogF_v=mo1zW)hFpz|vEj`*6$b^XeuofJjfpj{Ns}y%U^H`D;^tA>*?J z5E1bM)MsiKttHIW*4acD^cWVhAj`O(j=}`V*d57lAW^O&av0SqB(>Gd@)4Nm<378_lk4_{gdGa?*yv0QD0F4wE zGX3@qMV~ghwx#oQ|Ab+h`X5J~$@kZ2Uwq#BX!!{FvNjK}KLHwPGl^W|L{f2r? z;5QUEoGo8$+h5r3E1MqBcFoYm2iDuxoKTGMZCa3rW|CDHWif5}UOiFo$?dLmopH<*izw>NNO%s-%(tm&Fg;Z$CO zb*-&eop!g;?Cc$&Jcy9usQ|PdDj-xpc0FN35^Ehs;{g6Dn*8>(+g;yYPv+?LSJ;*1 zHzue5w$R9yyHiL;I+*oR*>LkbOl@Bj_Bk@ZkB|Z?MbwI4 zs9@4fw57?uYg)4;Yj5;)WLek8?7zIyrKldx&Ph>}I9AF>KY@2HVD zsFf0*=`y83(XM2&J?02Qey|7zN+`Us4ZGXYUl^P^e!`@qrDSZTFjP;NC{Zg(vsV+` zv&NbsoC|tq{c^ukUj)o|u{%%8sGm=|58!%JzBLH9fHPz-$WA`lER6}I=)Mvy&p|fC zt^74W==x7KJz&X)GX=gO8!a}w>eB?2;GrdnhoXC3o4fJ)66x?WzTOl^-;M+iN7Igv z0B0GY?{(XOrhY&50&5#w)o}Yr*4V9L|MZnEvk}>at_6?4e$8c)n)0}6OZ6^*cxf=2 z<%&j<697ABBfM@co7i#`{UG=!;2Rze)gM17S_gp(=nuc5Y7~$Dew@I0^<4+@&(%m_ z982-!%#Xg3fcU!$cn;vZE}go>jb{J5yD6;Kay7Sr+F$3z=OW6WQR~6nD*upd=B(f| z&Rt$bdJFN=gbh}?s%&h{+>HiQ2qbsgy44kjm%L+f?xELpQ?(GlUB`#Kb}Rq6nHNy5rR-6Hpu#d|%kY3Ko#o{6&Wo+zQHuN0IzDdN zT6vIv&_}GUY~}J-B*slm&3{V@A8#~8#J|&xWZuHNXHGB6_R-{Ws0^Vc213uBD6deo zYUVkCuwUfr#4lM>=*BzZx7K(a!vA&iYq;Nu0X9BQA(bW{Q!a5I8OxNh3?^UF;h{pZ z@r+qryYT%A@bw-JcX5|X%=rHL>wtE*|DHZ_(68n(mgueT>xO+v&MSP4>GS4S9|8&# z+1_7n-L0G-s`+z1oE_)YmG=(P`+YF4eSq9=GWVO~;+6amo@MoYeaIaYJXrgH|JCP3 zch0-I2_T+Cd7F*W@}A+EdATBK=Om)HwR&$G)3BZ`E*b{@d}MDv2;g2Oy~p?@HX)~P zTk&RsgbV4m)IxyOCF_yAn_nN~QA1r6J0mW7UyPH}raqc+eris;4|#;(r+`7-&a7k{ zsBOpHF*eQi@h~LesELITIY^G*S6`Jnhm5T~! z^!-uP$sy7YWVo~sr}u_)$X|T;pURp7qLS0QPCOo)vTR}LohtGyt2-Yxz9?!6pq9lV zKisj5k?qfzI`PBaj8xid!NJTPgMcQvIy|m?)#6WQeSi(FGUQh_*|_raRLRN*OqK;q zgSnC>g?v>ymsH^n<$hH zOncTDb-!x`X;A4z&^Obq?=iaiB(>esWF6i{muf@j15cx&`)No+-vjsqOr{Md5>g-s zrZ(LDgZy9Lgvp%8aEVTWx_}Na5W1pCy6mLCPwuv6iNHS5Lx(H=Yy4mTI!FJuNVN4~ z(I+eqr|W+&5AJ(2PJMLwoj7Xj7{`7^R)(1yO}u?Xucr3~|20x1q;uAY_Q;9LyN|fT z+Fz^vu;e1W0`RZMsH?XKBH*Ic*!>d=X|JYU_TL)R(l3kw6cOjIQ%{cHQ1ky)VbiDH zJH^Z{e~9!?6f$yu83Lajm!(P*Ft$M6VBcVC{Uu^-{mfxcoZv3(4a z%-;0ad-Xi@kFw-g)?!)YJj@d;0zA4M;jKLH9s=AlGuIm$U6P8%N$v1=TyMSvzgB87awXm)*S@^!X063YVJH;wrj7ME@=Vp8Bi&*+=2Ck{CBtMYmzqM=wB0&{`FD9S#^P{WaAgOU4GF5z`@%y>js%Hq-8~V?5wIV} zu~WY9}4R~)}qCMOzEJ^o-sR##GLI%R2tygGw=HA}GwRxM3NP&nd z8Tn^vauY74e5&s$iVHPcd&>6Xd=%$n5sa{DrYZPwj3w-YscHXH-otKR$$cqyYyBq_ zO}2AV&2xGi^!Grs1bvmt^buu^sCO>j-c1etbLHL?Jgm!J`_!HPeKPjz9Rm{b?F`qP zZ-mRZPd*M7XeWZgl77;i&d{Y+uk1>I{3nfwITKyz6+wVIgnVor-*-IhM z{BEC(rPbr$asS9@b-0_43lr*-FL%==24uVc)ZI952c$m0;%;FonGjAS``xKEK!G~Z zXPu0jmrf;j13%2%jZw4Y3u2MY0@AB%aOde#P`?k(AF81BBMmpaSrva6sK zlUy?!Q$g;DRx}cR?rXoKO^SA#y-E5LmE9SUgQ;`4EP?NMVf=0wyKInsl#MbMZl;jY zjRA~k6QK0VAvl_S^rhf@PY)M%4c&8XeI|cZOR50%S0#bqLDtUVU9Yr*M zwmAfCye5LDpeDu>A2d6z;FqnWPxj1pb>R32BjR92B7e5+HReGC#1pw@ z-V)U7`6fRC7_`CS?gn=|cWUZGu%vq=dyLQq9I;m~<%q*8qjxl;71qpDN}jz@((?;| zTCSes!5@8fIQ^s1Y^!kf9#TES9|EcHiKr6bppw_Fr6c@2t9X&Zk#k>dNJ#@;dL7n$ z)eAj5u&@)7b3HDGLY)-L-cT^5eboHL>^RQ(aBgx8Ye);qU?+G0*mo2_tasrUM1W?F z6n8N|<|=Aq$Sq<%YfP9tEZn1U&y9P8gL9?c__@oCOPiPTq>)a{!0FAFu@steYNqm} zPm7X}1|=&THzN9d`nW(6J@LRh8ihrA3z?joZg>qn_p7-$HFfThcB}he{D|cpD*`f2 z6G>aTO|BF_A(7wap4B{H3mM6+XYR)fWN`fWsmy==Z~Z?S|NhrMe?C1v-|%lNKVKiP z<>J>zFmHSLay0F22Yzk|aM|{B*)-Kw@g}8>J|`dEQghI8g)29HX|UzM@l>?pxceg6 z>gI-!hwavq74k^m%jlxqRo=oJNe%U1xPzs(j|9hd=aj++hiM*-e=2|#r0h51V9n#o zvEFpLteo=lgn;T9CqA5;s<;iHhu3lcF}!`_%jF#D3zxl7Fw(xdAN2NaoQiP8F`?dsy)PDc5~nlGbVNM> zKNx*QNATqB=z5Fw+)Lagjs!KT!fGiJ_%z@!`pj!{O;j3cmY(~OK29%1$s>~7IKg;5 z9~>lgdA)?&hc9Fm&VoWmZ_4puxgQ06fQ?@ZB%p{au}6gLR`DW*BS(wO_h7(V`a_G$ zr%QBAHS48km(HC*9}l z>dBb(NcRTNUZB93?^68~9j)+jh(8htC%W1-L0{ zY+XomyHfGP|2eJ3XqWOsn!itCsh$%chl)tbuainK^H`DK!>L;s{|&ZJ z%tdmi3(7ZzwV^BdQt?r)s@=Ly7EVCLPJUVIEpo>qFm^?XHe}f$Bhqk7jQ0`{C~Z>( znKJSYTRH6KXFAV==~cyF;}Dl}Ekt>p_7=L9_wC21 zDq6hGO|{i~-H!V?JZ$a5yf{xmypikRU;^)792Q3i&y+V;LIL&%QNFKM#8cGH6NNBp zu$>qgvW7{iwK?bQY%;EQoO*{I%WQ3&ir%ir`N$GZ% z{hLuw9FT28x2(2J9y(sXbEUQk>m@=Y%#*8G?l`dGd|3c1K{TyQQr^J!Ze&0hwFvQD zGXCw4cw43&C{(`G^oonNNTO?%qF=syZXh16FBLSvui0(R{Kb-o3?}{Y;47)4xFe0X z(P~;gbZ|GxK4|sU>5skHsIHD4=D@YfAWdp%^5zIPx}qa~Y58kd9B>-9_Tcy^BfYnK zr=pi-N3cw4(M|gtAtbqvy)|Vv7`5=^c#(((#M4`kT)S*G62xlTKCUdxnkF7(E2|Ig ztEM>v?qP8tYef^e`+KG27iU#oG#dyqcf18Qjs!O_PP%nR%ql2$r(9YGg~lZnGliB9 z*;q1QbupFKdcVfYYeZz>`<#-M|LM!!V%Z2{R&-4xqhMg_7Lg8qE}cQ&VPN?_Dd6oy zB~z1h+Edv2$~y$M_tAL|eYBvFjOp|VucZ_8*T?iA?T;Hqzuiy#XpsS3)uofzfr~KM zzuzYt2*gKWtn4>@CyR2HHvi|p@c$)8pX>Y=K6&uX`q$n17cD-ovOcf)`be^M+}hOH zl$jBqob z-t#oA1Xq#2hYq&@Nr}ej^p{fu&@60LJmD-cGTQ4ZtN(?6fD~;g|3=I25OFEw%gAfMzA8gGf7e=CybEpax#zR6{Bqu~(Pu2LNQdnyBfYnK4{%Js*hMY>=A*+rW|7gzm2`)adOq%R0` zvCgN}M3k2eDDa1nT(aDPj+~~A?yCJ8z-C6Pa{k6Cidq$iDW{CS6y1N=Ujl_KZ%v&I zPQ;DghB_{_PE)R3^7_4r{~*cP)iO)=t_n3$?TQecO@{~v#UMjT!$z|;IApx(a)UU% zR^*21R%RMtY?e~82Ut?G2R{y-2W?T2N59o{KLD6CkdaV;Z+-nzUK=LK&U-3>yC3Iw zqYsQ?=VF>eZA)+mqc5b&(6Ps`m7oD%h^(H?`JEEF=8rW(c zXbLhfE;ZkT$NhTiG96G2iuGk%_Qr(Sec4~jAT0xyfbU-wPw*s~WebdMi=*g0fq<|u zCf!vZ<*x2bzr?$*z{J@j?A_~y?=pc>Om29rHY+!9>el)r-*vh}r6XryEc-ED`p|ooH@cfG94GE}rfre( z{-o()Y(5?5vE?otIn1|S_f27k+?@vU*rg*T9scMu6Z{C<1^P^~mma5Ky7gxCQdu6PG*JrR~l>P-UJm z5&@<{v*mVI;7!2uL`Dwxx+{r2eQfP#CO;%(T{lDGJ)}TDo=1{l5}`-6ynrwgKe8EA z@3B*el=A-Y^!d)|B_g!jmvhcxe=g5VHoc=L&D+8}dNCfNPMAiUfSa zsyK5QSXxVN7~7rAmL#||^L?hL_F>*=GK8MXkj%-_pd>T*iMv*hxGsd_@#UYNH9Z@D z4*$C1C7Xi-T&jhvT^>3qAlN2z*=t9S(4#^BcG;7n9QwTvk_4YhhmyOo{m2EBPI!Oy zIFD50VQ8F(6WH+d--Fq5T^L|ZL;wCjaq~zW-@w*$(?=Vkxz& zh0QxVv3ijUS|ay2%BOoKbj4$o>EIl@POWGpBkD@i=Q`NG+NU0?_SdRWW zCBo&?!vlSY2WvGZUdU#JSyv6~1y*G>zmPyCYSr};sxpA#)9^@gYg{H{AfVEeWRi5Tyw2z`}*?*Hg`PeTXxKb7GJpQf$6)7hQ8=QsXk z;jWU&3_+tTxyD`2kYc*QHj@Q*`&rjoihnu%^PkJJx*GK9n zsP#Mcl>bEW?AAXU<5xO796MF@`FP6hvh5Pj^2kWBEHs%Zd_iy=q(nR4!6K7#2eAA* z4e&>1+HiaLD^Khn>w@)|z)$+uh(Wjw_e3>UjlaefHBR|H@<#nrKjdqM;- z{ktZtb)V6O+ry7ghI~Kt4q0L9V6Mg#(Q57F?rBeJEgT8ebg4E%$B)?Z{8HH((6r8c za~X$IaAisoD0(_qQ3mtnl~w5BsPhF{gyBI&fhr8?Fy<4ITqo?0VN#0^Hji^oxBX7K zpH0_c;^~@`8$hnm!_@0T7G7^CThMN5l7L=gHxI>oAmuI^bE|h~Iv(h@;4X(v=ScH& zci!py>s#&2{5e;{?M*qPLWK*N$qsZcNW(L*4~nfa+Kg0v;*=8fnu0r~w;k^W&UtZw z2bMK2HMxzwfU5hHyHMH;PscTha8ZgSH~crCe8HxJ1{q|%(I*|1H`KGNxeJjQzEa%t z*F?-|Q(@4Np;8LP#th$$YZ{f(l?F2M_jiQ_4p9>S!0dT&rG~L9y4#xl34en z=8OGWI@ZtUMra>Xhwe7tr8qvm^SZ&)JN@jM?;)U3l`ELDJR1VUP`Q~S7xONOeR6*H zKjXW|&{J(I|GnHTERHY0OTn6ax?7jHo8}qNO-OQ5P~uVwMl2br0MTqfl1Lj@S!fq$AL{>oj1D zqDj^-s@`K}1*OwP%6Q(6Z`!gOGk!XC9nbxPn_hs=uoJl?r(u+$~FHPw_$z-~J z_6ni(`Iz&01a^dl23hCiw?CuLt3MXwUjm$0!>-$#U(I7fd%wRI;NP(Fgi?Utx1@Uh zveIu9@FBwoGv6h@Kl+8q{6fM}b6N93KrPLW_BjVzp)?VXH%d9jd!A?*{fm!@`=~*C z?q{pm((28rwKp2)&Y2j@`H$7Xz*?19k?&fumMj@ywJYX#$2DS`mux!${SoeY9_AN0 zeC#7nGQAmHb((oZekf%N;dlnB2HRXh;hlh|z^ zzl&`Lei7P8_dpNR(dQ*Ey)gEdXzBFp@+Y+HQp#8EnMW;%E1{e4<~~P91%RZEJB+*4 z=PN1$OAYg%cN*$$CM6Eb3`s7@J$CF-_3Z=Qlew3Qf9`Uu$1%`~^rl?^u4KSRTKzh# zLmjuA?z4JxkrdhO-4@zAS+U~tXzZkS_LC3uz06+^-l2EqW{Wi)9Y}uN#D1gGkCL1T^QT>|i2jNqJyQL% zGZx1n^UG+oz1vXBY1(H?KVJf<_nhqZ77)7b#k49SW9aeod*dkgkJdENJ2i7y`a{+U zF>d-tREqCf6RrT1^d1!t6jZYWHC4M)@}>O)4Q`2Z*2H6g^;yH3f1f-%II?#zYO0$A zlEfZHUj#w#|3vTq3_axP;(jfu(TXiZjK1!|6x<)f6<1Uf$K&;NnsZi#$aPXmb2(a5 zQgw6|+<}YCU@DD?ipK1dy_x&k+%udxEFaih^tLT>_VO^JtGF=+oqGn^S5-Xw-M`EW;k|Mhs*zuM1R|0aVE_J98;{@(>X z=>hm`6mF$eg_{|tKW5h)ZHGBHmH=kuG-eTy!wd){k!t%tA~{n zYM+$W&*BAXO6E%pbMogvAvxLy~kuXJ*{28 zc%Qo5p~vs{M%!yz0UT;?7x3tp!TLgsoBj@}=%v{utx+=Q_SicBcLX(6d!^im%ZY(A z-^IJunM`M~=JD)s{J33=zb6~L=5&6Xk2ZV=LSwJJ^Vp7P?{)I~d+j|F-7q`8ea(Z7 zpZc!if5<2PgSV2Ky2r3rFN2@XRJ@%T2m7ZG$#toA(wFITCnCEhySt#)xo$;CBOhM$ z@NW@mzmi0Ii9OWbip=&NSy%2E4*~3ixdV<4shK6d6=0FkgVaX3imrlEtG}!1ZQK%F zavJ)&XjpSgZi{+&a=Pbw#s5Sg$``%MTgSbn-l3tv*8rnF2civGMFGUREZgCOuY`)5 zrND}v*F}fmvgA@BGlhv=%0`>?QuuOf+?h|JTXq=8*kKR2n_TuPiv*)1;B|Pym8iRaI z%^0nlKg6x$-g$Q;F*0N5JdAY;PB@fEtO$SL=l~)}+~K*Bz+Lgg3wwA^tm@GU8~pQU zAAbI%PKLXaV5PxBYCH&WN$zJk_8|UqvKxL`AX4$`UP8U=gtF@2l$dD+Fa`6>$?p-_ zV7(#6&B?D>cyrHVqni!zX`$+IsdUg(?M^9Ie~5;p1QyTzb$dUt<{(HnCGyRIWMv&h zd(+`-uZI^58lkZ#z4IlmYreb79(f02-NALi_)p4@sIUJPa`VahNg{U|=BaY`Vcty& zHW=FdQceFaGl$h@72A{h_?M|f>b6h{{A0mv@Zg#Cy{I4yWt-}`<+&?#!20cOCd9qm zt^FUm+ZyzYLy{1r&!9FGlbrspLF;~`-5g;u6na$&*x~d^pdJzQ19uA`pGs|~A}T@F zJGHXf;(1#O^AwQ+_ljSRw;J3nl+J1EiMt`xBX|4n>vfZS z<91pG!)BfluOpGN!AV0AKld;RA~d~H*z9DqQ2N>kJn~d`41&S1&*Hx@Mx1bacb6jV z)ftCT=MS&vZpa6kwAr0qbFOdYhm6h*_v(nf8PPrPYmU#rH>_T$6mCviv3rk^dkHBY zW;(I9Y};oVR*tsT%sjT_ofYn5!b2I&%*Q*|l4ip`={%Kdc!#Z6cZ~Pe%C~wa<}HJj zuE~657(8aAy=;T>G^m*`Sed{Zfk^ainw`HRqmIAs0`Dg+g1@)%$xa1| z8msSn^(zU+J2jTjFe?=@kUxk}Y6d2l2Xe3(glNYItDANN$U_s&RaN3L}>Hn1-w zc2MURzd+d=oupr^fzR3S0qD(}4$lJJ<8_rvNjuT7tRbYvy? zo9|NQMT_YB_pkU5y?CFn+c!=tA|00rroU0_hc$dE5q&*WJnjU4Re<{fJ5O9|V#P_4 zTWq6iRI)eFJZ9`!milZESk9Qf^WM>x#e9r^ab;^u&I^Dd0!J=>WaPlvCc&b23r-gz z&TA*^i1a9OsLY|=*JS-IDzJNMf0=W!mb9@|9 z{qJX8GpoKGjj1`{Y}tIT_OjT;*{`#!1X*T^81eBUbGUhSEIxbjQSVmZ?BY#Hd8QBs zeKmFVvuLMaMq)>u!!eL0Ck*Os0AleE!l53dJYJlz&UGh1WKWjGFMH&WgPQwZE{QkKM(@6(2Xfl>-Z0QXL(zUm#laPnB(EW}^C4Q*fHIwZshy~vDJp!&pVyX9`QE~}& zMMRlPj!O*nJ}Mr0i0A(g8liJfcd#aqltJ}}60@X7U5UeS%meyvj7u%v<|V{r>LrDH zHtxOgL`e=lQg$EyTK*^6&}1X%_*PhAF?v5B5gp6L{eaR(?oEWIJLy37*#isvrn_xv z=zO5Va-9JCqzQqn9-R&iMws+5O}F3G$tQh$sp(DSV}>``_}CEROPB-lARIDi7|#s{ zU+C{o3{o`<3x0z8{2QC89?zwHeaP_d1l;w4j|0w7lK&Lgm0xcKfdZ#!zI5wxg6&6o zxBU8=AWx9xn~9+p$$7rkM;i$Bu4_^~BZFz-p3j2XNO@iYHjR-F%{lQXn3dR&X}2XC z)9eUx)by7%w;9r2y*R@nkc4gW8vQHE| zBRQ|V$WR|!eMb-2hObEx9W>C&_-6n*drQhIg^Hm9b`LkPD6vTf^fj4sl3`6ES8S?@ z#U`MR-(jCgKJow?4Y7A{KuD9GP&noOLv8GJ?O1b8@2YoGq&JBYkus-aYp_#cVWdg0 z-h?=B>HQ3c(mP!*lxMN|>10_Igu6=~lx^2iAxIeQ{Y^{y@b+$lOzr+q1+c(l0%~dC zm0j{HG+T^&bT*^#%g|%fZ0iEKe8kXzw%B|~-hV&qn#amz-(PM8xsu^eL49a~S9-hr zy1Hcy&T9wPV*?vG?>kJ?zg1GH=b=$@3iZn&az|kbVxV_hdCK-d(112l{n%8F>^gpx zi}|vgp1!Y4iQ}6AW4X%#DVDzTI_ZSTL8;z>MK69Kmf|Zm)KZ(8bc+_PHFR)P3kfb- z6dAJz8RGIKvj#CHed>`ZqLYv9T$V&q>@$2ZyQxtCa&sH`5yl--nw%3XLFo2ox@-&N zNlM}n3W*MyV9*&IUu94%Sa!mq+yeXPW3XPYLHBX;(6yHk$rfk<@HHNYV}jk{j_%lE zPVj73@@4d`uW|zZ^IJKG%ZlRkiXPBudrOMwq7f~HGSb#r%FBJDVtI4*fp`?mkl3Nl z$B3IuIW>Fn zlx%8Qilx>umlwW zAW(Pf5gISMJE^JYL|rS_4jQ_@FKKcclh!ACHc~7kuG17bb@Ttw-8$dy<`RY*{ZK&l zTBf)|L&|4(KFqnPlf+J~G6$dI2RvuyZgabUU{z3C1Dt07GK`A%2ksc?%vI$*+mW7e z5W%$FX)u*RN$vt|)4^_DPuwkZAp5{B`Z$?evE5z#x}B}_M@p<4uV!6#z1COHx0#S% zyzaSvoIxu9@tuzrRC!a=gNzK;#zM+iG9`;HS z9*BGfpyS|@=7u6z)f%=)8ZOjz7po4KB4LY>Z)FRuJZ?Hfo3C|@L-?}sztC{uMN}LH zu3;>Go_HbG_$|HJYhuZb)10x+ze8Lj1_()-a%%a`dqrLI!+-uxzILL;4=bXeC4Zmu z#uhuNiZ6l^SSr{}DmIYc#)d3gc~y?P^l}|+kBy4o-tUAzokJd-05RaJzRtBI7;Y@|%#}!sL93blx8TpU>Hk@-?kEW4^H4ipI_rl>4Q;i@mW+ws+z_ zIHkz?FBEwW0xDiH-@h=@UU)c>*t=13HG>K`UMn_IaPE7HlebfrKHbkaM{Hy3{V?wo zl8DyUI6R;*o$NN*-*pKxBFE)Vu)4O z4E&C@Gox8>bH{)%x(FznB)cr#J$BYNkC`M4zGZ)$XJi0sMqExh!My$28lPG6?j92} zvXLGK&862vU^~K~#LM6as>EV_Ky}Wk-Ze7LX-@F4ck1+LAAcQF-t|t}RCvf02|qks z00zccIAJbSxM$Qi&L74N&5!PRqttd=!?Ko1e7h|28Z>`o+y5N0 zy7$!jG{#Hbr*>bxr}mDeE80eaw#LlBbqBvU>gpvxO}(0N3AD~%iF}W3(`E~rFwr}T zQ9>|kt{X)W97rJ7x+*`h+bP(PCcoW*YSY~JCp#{+PcFv&2M}`|;p@4YiF^0oeF9El zSnqJw2X%9u)i^#Mz!eZUeX})L&_E&)%sC?FW$!cJrx6aGRd#PFuXwXX&b3ghM|v@{ zJE`laGldS|c)$%vKA`%vxt0act5FDyj;B=?Ow7WMF8Us-2YvEDJEL=Z+u(Ti(nM6n z!oJaa!tj>qR282xBa=@RzSQz7e;Pvx5Y`BseVXTHfknoX^Lq;>NPKd+r1#^CM?DH}+% z$4+U$^*Fa0~&t5TQ6hrDmvIlWiy?L}8G=FO0| zELbAlE$H&tnk#2ZlKuAP33x?Ji<@9EpAGBH%YDM?<^cI3>yi`XHwVZ)1&#se%=r6qkzYfWQE>Y=}SSc=>tCTl^54<@Ut7MpO^jcl(yYJx| z2K5<5uLP33{tmOdIhGL;<>sXC8qoJ<>fO@MxFE5(2xrkvkIN z1r31WZ3j(0F7I*yed}%g{y44}rmdj)|p3xJolSsM)WMkICipiZ-`eikZgt(Vyj0x^mGUE#jUbU~ za2KfU#NE7qzZ%pAbf;@w!dh;Sb>rTxn1aAJByLuSBfP*I*lO^me2-Z?t1|ND3xa@H z#B5oy=YIiE==uw>X)e$EFZ-JQk7Jts?Pqwz*>`dd+1)>#>D@eP^?hLt{32qJ*3xKQ zNaWNx%^1?k^dj}vRnDZ`oA|IL@oC!|D~z{f4XH~$>ZtpQBheOjBW5qu`lq{jevIYE z6dru=FGth~ZM|YSBr7n;z9Y$|Yr8VL4|>``tdVx-z+s1?M!vZDwsQ|#nG^1)lozr} zj!aKKsOHE`gB3c?zQVYRUp1eyj7H{`9MN)&`c1m^AFXpMzJ*iK;!y^aBKd3M=y z>8ilUMuSZg-~pL7HIB(nbg<-=t43sL_eG@P?5F&`$~dBPTPA&eB0#9z;XU&Dpn0W4Q2%6#@O zyffP0j#7rV$mS~m?G2wol&%hO{)@ItHCy986!KyB{dp%7){YWN>~iBlpm3vT?md_v z2E3={uNTUk$Esp}JhRhtuYW!{gS-cr$fyqxY|lAYETy_YawJw8A% zPK!tHGOgH{M6iIX2B=^#$yGh8_kp+ThIV+rElF8LX;1=8fa_&xjZad1FxEtC&%+ZL zzf@RMJu}Qah2>X&6UNe%bZWPX;_-`Q4sI(31j~M+N+(8@Eg%=c#OQo@0Ur$=d6=$_ zoVRORNsm6IBYm*LzSlvU+60CA49Kg_Yj>oZG2JX@EP@?vTb5_Hnz50rT3QLP6}A?cduZ z5pGc+75$6gxr!Y8wgvT@bTKQ#Ww-2RaJs#0{bJ@KQLkaW0r}?UD~D*r#f$l za=CKy0c&@60Yc}l9I3{_Tpsuq56y(lbvJd&)jt_=cxDQ1%4MTHdhbuxgR>{X(}XyChcxyC`BP>cd7yb=S|zcMz?5Av ze26txfO(fXB5Tu84tPoby&9cVuD?92?0vKq{jfLr%xGilzxC_`ugjRiwA_$PtrOd4 ztIa2ilLeAq&^`8lqb!5!d}34+d3Jr0%MBRWXf=#;Bce5&6uKEb?Y@%rbk#i@AB4vt z$w#Loixtlipw%=?CNX#tSjfjjW3Rc{h1vNAFM+VD7v|@-Co&8%?H!6?j@rfaCRO$l zGR%6*F>pL6O%UOB-u#S_pH)(IajYD%l{Kw;Fz|?M#}eYUH0sdK3Yt@O2NSMH2TGnww}YON?vmSd&C`1r@+fs$@>G*dumQc={ReWr zw}Ww8S`;`hH?wZ_w!Le^y{xvOV@soAlk0=6=t^ zcpL&1hxX!2iFwSO&RryuyNA`=tR>RD4#Z2VUH0OfO}`d(g8XvJwV@!LeEJYyWBlO1-%J!?!_DWc^M z3pAB#M`ljg7KF2uyP?CUENgOpmoN(3vB=%uiB&UC6g5WK{h9pE3-2qF_U+m{QKz&LcERdAQhK9m*YGdr z%uk^I`$YWk@17nmVDGJb{oV6_Ih{{VzbfbT@ORaPbhfz0ij_~@vG)z6>=tp;BHNBQ zBm2sO{Ej_1anQaBj@BeFv@&qx*#d{f|6PK>iM=_2$Z+WQ0P_`v4G$f)UJyf)97oQ@ z$hP6O92Sj?d*0@>k!`ZuJQLJ(!u@33g%Z~KnIpqI`Di^SKzsb_osRe{wH_M0SvMkl zLWhs2sE(nkRjFO}_JG8eC+lRFTLaRLh_1eW~D9-rm3R?e--5ONDFH{_&)x< z(!jl_p1RVWW|!pOZy=98H34>=Clrol;HBfgOTaS-oEzFhiu)Vn18hSbj}nWlQg z^HiWbdB03jhu~q}^Is@gW}38|xZeDpft>2yEX!)Uck1e8)5&C=eJt`hwC!YKS=oH{ z4q}|(b-cAs2}%q*&qS-<1xL^BBF2*srjDVZL9o*Q{dUuaOse)J&F&yKObC3gh?8Q) z%T^XTbR5=uJQh&w*9oLm84<{b`u$S3pfug#W>>vCq*`S5x)?=kJevQoztij&rspf}E0hO#5A#JbD}y2YLyiMh4gTi=xR-pzId;xtnQ5m3ap(&@rS|I) zagBkycX{&MNOCTtMuhy2=$&)G;pJy{OsKZ~IMkJBs^7Zz!I+&7v|IQ3B`cjBtECXo zm#d_nxTK@^Wf7Aj2_@ooQy1F2O>J-W!JQ%uh?5U%Jg{toW9CyUPs!WBwQhP6>=V+6 z@c}0>OofF1*im8_$#$n;exXZ@(Xkb6_ zTvG@)L^CI@A89YP_pL=Pf2SUC7?bl3HjGB9vdpJ#n4``1yXvihEZVg_| z3hset54}Ga`Ix{4_Cy5!P()N3;)G~Is*oTgMruz;N#w+hnf9Hj>nTvIH`1pAvZk=t z=@hEg&UqTwo^`$)`nXM@)!VS8<2sKV%Mnk8#3TA0S)lwxbcYL%pbjF&t*DFqBIf}r z!P$yW9*HBUEaQ`ht0eo8!oW3665$YBHn0R{iFl*d!Dh=PCvsP&B+Yq09+Nmu*lzR1 zkeS)#@wRv|7Q1H~V`GTprXf01b>Wo=yb4TT0faw;4u6{JNjtrv?}w=;;M>C!Y9+zD_d8r@Z`pmk*@&$>Ag*gxHS901$A0cI(<-!WnL%!lx6E*E5yS z#~W#S7aC$o?!uY6)aE~!H1&Ywza?)K_c-ZgVx0+iFpDIWS9kFCiCB%@s3EVKiSCmV zQ4@{&q2q17DS6Aq2{>A#90#t_iKr5-MDUS#6Dj9D7T1Y@7&yLCk1x* z`i2wWlk3DygFM)}p5DSKgWVVynLJr5uwLFEn>almQz>JwRu^vLikRx5PA`i#kkLML zRAI?&#B_+VJH%|ZvmfbZ`KIdtHG6@|W#4f;NtoLO0=?X4!2sPGYE*Yz1mOE#v3^QN z9#xU&L!!RU<=EX7st0UNO+TS_0w6!c>sFYBaO*u+)eNIuFrJ8g5p`j(8qp~ZIAjWn zj6!L&5#xmBJOQ6NMU#{S!jLIY)Inf-TTF8W;+i_qja`z+!D6b=cC+Mj?s&mCgsaMEs-=Y$F$_; z)iycvqV~ubzT`VTm%pXYO(ZUWT+Wp?CF*^$OkPkmTs(PuA?s>?J3aj!Sv3zElhfmw zm17E5n6ht3&K(PP{)GmN+G7UJBc6@9ZE^EpMEuDaZN*;u5dXx8fiUuTDtc;xxEt1f zq~Dq&%-)l~o3%j(oZrOZH-Q>W+XR>6t_dd~A*l9x!2A{Ej7?l8ogFj@v8;)v$IA*R zQu5WAlV?PPnrP;0k+xj5r=N{`)3sl_`px%)EWa_IEsgyv2>|GcrkOmOzj`-Rcmy}n zkCvu9z*Z9Z_A=t0Lzg6%b~e+5!8eOtKa0||hXSP>^=&re4Abh$@n+FlL#1yvf^_|L z{Bv+T9W2`!ofaU@dr#1hW8{%D#0DA4`sA(Q=0Mc{YZVf*h7&5fsSroj*Q`@_hoDch zp~E%s^nSKnvANrt-={(x)_KiF{dd%ScqdhRV!GP6xvRvAd_he`gdrDNk6b@S*}r}x zZ|lrYP+TUO;E7csCwuQ?^x!NhBGOuml+b!y0W~cE^?qtJT#H7QOJ!Qf+f1a^`ZLoNHOc4MfVC^c^-~TNM_~*t2llKo7SR01ueb zQ99|SERf-xc@Sgl5 zhA$=eh-FOErvdL13b4(P!^S(0Aiq1qzwGh9ci`X2|B26}b*#6Lt|&e^NR$uu<11TB#mv_GV1=DIE#fsTt&r7 zU%dRQSFccq@R;>ZtH;2X{&#JQiei!TxWd=JJwnsLWqU`bO*^=g0D1#IiXi9F@+Zi$ z<0G&_c)sSSnLj5!TinH1+i%3X+Iuj=@qQHVRZxfZLx(R0{?=9RkEa5^i|Bs(=og>= zu4=x#rn&;)qE0XnLW+MK75xkbLoT%26WosSTO4}!SvvEZ6iD=f2NZPE=$#j}_SRl< zLlpzGuKI{ea0~8_dL6gT-WR-7(TiFa0G-KR6KKT8U`Jao)sW;*-~3DO5aLdqMpyNw zqq<|^HS0-4B&o7gO1yZwIOz)4Ztri&RSEq=^k}gwaH#QTrI7dCBG<61gdrGUto?zE zNDy{9w|4=%^yqxEAMC$Qm#`Nt&cXp2w2N6A9h;&C}o!{It1jO@2Tj7*OiA~6q@HMMq%XTn9#+nr zQL{xsUgpIIw<)$Yj_O|A{auW8$LU_R^K!|0Mx|ul_M4d{WQ~P7IrX(Zo;w-2|ID0Ddh_Ph zA(58M)th-H=FU(PiSgK*N>lpeh#Y#}0Jocf`Fn{`%at2Z&dG`ajDDA<)q+QSx>;^SJapXG7OSN^=0ZE9?k+!wS=L6GiU4-& z5Q;X%N~bZ3LfDN2TJ6@1IB7$SAsH&?TQ9i@<7+GZ;h!Dq%Ud_wPFa&Tjfi>im5bHm zE4I(0lsEFt>HNh8jxur7hx_YML%(JLI1`O;(AdhowsQt+O*XSC4i|I3_dMNU#Nig9d)<}Z>zJm&y={Q-&Awn{4m|$)48Y8X@6Ww zmC0!`Z?J%zNphsEr+mJ39A;Xeb(s8y_thtrJrVIce{A7-i>E{qQ|1>#ry@QF+bsD> zWZUD0t(7-Eud1^>Ibwam(J|ypxk=uSxiQCIsCC ziO&Zp6FwWewLI24|Dl3SO-Eqe6CFDGF%D(Qnm_@SwMgiRSyyUrbb`!p{NAd1D4F~t z51`C#*l-i82Ux4`NH$y^(a#&)z|CVXEjM`NMn3zo$8H)nD{1F>nBRRKV~oQs&uB)E zA4#*eFz;m0>?G5!Bq5hnNu1x{MlO0PgKAkl93ltA=8w}({+3b;@;g^{*0Q8_5#+`| z3UneinBxOi%!-E~zfjWB+vbh?d%JV5DM_x;RsnO^sbzbyZ&Ib zvO&!sOtrSX0|rDoI~SaaTL_I|Z$23#UB2u%J`1ere#5?Z5r+J62X$6H{U3r4V(;!umR&?_j;dbuiE#Y+kcN z7$@@yhu|3ZIZ^4jiMsZLjKP9HV=Ul+(S zBeEpG4D1GV(|CBZuwb8jSNPVrz0Zniq2T9_ViD+HnD}VmUw8ld&+eNF&61o(`NMCb zgB%0rbylF~}QueQ1 z^_tShD&;K{Zz=9RuuC_c?UHbuYfJq}b>EH2ZiBs8 zk1~QJmXfoSCJ(s)fc2`qq?6rP65OW{aF!wS(F8)JwO-z$3C3?^6z3~dJeylUxe}@7P z4$_=s>Y>TuxT(C8zU^Zm_X7l(E@pr9)X5(qsIMO6nJ&N3NNyyU;|p8@NX&(i=$Roi z8yl47>~z^P#+vt!WvmpNjORrsXpnyl*7yga+hRDk(xOw;&C|FANlLnn-2IIX_5`Ri z?>q8qgya;$B1yl38i&jUpR?C;&A`bk22|glfnC&so=Q`9H$?fQlt+Qo+V&0@5b5j@Cl4T7t<42D!M8V;j0TqF_XuqH zwzc-)2U8h7UL#6Aej(U%KdOZFOXTMls+XGiXA@j0*|4NLXcJFi_G41!F6%$Nktt^) zN}7rQQ?FDeH@|rBS$m-2D7rw#<)91$XxRt_!SNziXI# z_aYl@c{+uj?RHU?+S`yuW)6=zVhV6hf{iNNo$9CT$YLBRN7WD9(PYYE^okFO_RF}I zb809M8hXdE^lBgS&UOr8Pj@6N8@uPF^rt>!07Dre6I0lsgP^X&Q1 zRekJn@q2%_>LF;lz5TzMgUC~sB$)h*j=j$MhS46}H;-k;H}v@De~x_cX5GDsr=Brz z-#N@fAKbAPBUn{(cus9?G6BQOi9?bXFt(|JKO5$8B5(<-t;I?ff5XeIPciF5iEGy_ zt=oR<*MctwxY%h8b;1i*W+~nZD0^&mP4^sTx@7qa`(B5%9hBk0udWx4JES&y?|Jge zujImt|WtZ7Kodpx_Im^!0) zhrf|JvyBp7UbAw!Z(R7O>%dG?BV5_T!2Hnj|8>1+;?JVcunv!}tCTRs3hXvE>rl)Q zP%_0~!sU0FZo()(T5A1XTvzXcQV8IK+PAk@p{M1j({`_7=(o#o69o+R;GV+{u}%9f zT(8%DHP3z5VHLrITV9;{Pe7&qi$4@4I7Nf%%UG zQr^*nJ_AktW39j`)O0$Ax>|?;P(ZK0YsoH-9%++32rtXgK_P8pm|<4e>yS<@R2AE&YUOe9!Q1eAe)( z199}l7Z1#ZUfge}AWwJANh(l}5(Haa(E&wdTo*KNr3{BLFqMIMp=&gbI)ZPO!uIYwyu!MgahDu?f(*wqvbD*P`qO{-7|>%VbgCEIFg&NWQAkvoe;v~ zqPsSBdKW(4o(qXt~H{MX}YNNUpztnX6HP1$kA8L^*wNM+ilZ_cR^NKcNC_itBIm;!7Lux(Ptj3?Y7LnZdF|{IJL1IdbMm zf(99Vh`BJ2IwL35|FC5~rWC$3of_1xy)GYEP1OT$D?UjqOUqYW!83U;@@>kEy;Ud| zv4BSfQmS%gA4O%gVewV4+@~>Ybv>1cSFWV3N^6>%7|O9J9tf+ zVTGPfM-Rs>A%9nPo+xSR4;UFjqMi2LxQHY?#z9zP@t43+{;f>i?NWUic*m4aE}M(H ze_A&x{EgktjGW&8cxZl!Bq~36Iv3oov`&h;ld#>fYB*bzZldR>0I3Ekdehf$3@{|(4oJ4kt~2C+zdB$+54@%{I}s4p2U5uAJCB*)tB z<{lY%Md4cxvz0}3o@Q0}x;ue;dL82UX)3%0ijX+oaRVchWdbNTl1H9z{%;|uNw z;4c3Mb)*r&BUeP(?|p13^j)ElYmS5n1pcUXwp zvY5!BC{ba*FMe}h#O6MRtc!@h?Nh6fS2L2z+mb>=5~Ex}1An6OwOVk;gRb=7H`V+a zeR5PKoO*g_zHx?(Gl9yWNIsqNw~pGQtw!r_#zBo2`Q02_vIj%nQ+j5~Hmy>=YGRlG zj~`~(_1U;#=f_-3^gi9lz7ad1=|j--`8J!+pRe@~b3LEW4wuF?0``Acna5$1U+#KH znr>eo5Bvg}qHvy|uHCXl?zo93KlxdABU^7f^Ul6|b2rb29{QvQGcm_+;cJ1)0PSGsO$YH{!ykLs zFR$r`-VgTB`#_&6QL@OpACx*xMjJ+uowMX^{(k{ z*z!kmq7!p@gpIp4>R7Luf+CjD`EG&(g`Xe?e$!+A8KW4EAum1_y0QwPYl#;J646uK zan_(3*s+ww2$k>+qiJ#vde#mdDpwykoEx@oIjh}y%b?)gqDNupAVrK)&mHaTR)XY4 zi&G_Dfn%j}-#~SJnp{X}0KzwH6h8Ud&}Crx0-kR4O@yfF=>Ct+!p9$IoNP||(aA4C z6!x9}cio{)Exm_c+wk1`B>k%YqR-Uu2VkS$hT&xGnhQO13)3YL6FgGyllETM#lL^z z145qP%YUyA3mz~SJhadJ5YkxRr!Ta6+i613fMbYzpd8{Ueby`Jp`ivRwxr%M6SrJki<%N}o!<_MRijHvNaf z-VgRDalAI$sWR#w>pm&o86_`zh4{ov{s1jHS{+_xEfrNpb1#Bf9dAZSzd~=9f6Gb8 zyMN-4+vK^un?$7?F8#VbJBzZs7;nh*#0&c_xo&XYa|mniELWx5~3=M@$+X?%1^Oz-PC;gpw5Pm(r;Ke}EfqZ)R zNM0CtZFuS0{UNxF@#f|z-u9hixfNmNy)2~%04QiRf{G=2(T^3o0Y0jX<4zMd8qQ1OTANC!YT8k1y8Or-sw_Tr(pv z`ukbO)J_2Q?>+uG8m+&}etb6Fc+u;eH>npwv;(<+TmNy>R`&5cfjU!+wlH3bS2Md6 z+M8`+Plc{ojjO@B)|5MuF<}5^QJ#{2FGNO3Cw-W!jnuY zr<$Hfx&iR+{JpqY;42wps>*zX#vO$uCgg%;Pt>{B$!l#N-|kWdNTZR(>L?UlbcucEA`{Y^YQ;*4RU_< z`0DXN!oYL?e|0~eKYsS?@p}IJUj6L#554~ALyzvN9-5}xzx(2sofm#yy-?X!i@33e zF=pUlTcP(_t;dLpx_dc%)=$}^_+#(vwvKWav3d+mnFVkOLz>gI;ueohPjQNq%;a

    @Jq3cMVK$Pl4@;^n|q9E(7iVI@}Zyxhc7#OIY+*!cjPh#f5&x6R{H8;%HL$0sT<=R`gXWX;HwV3@*fjSexZt?>tERKV7NChr4=PH_Q*7qXe{EbWOZNSwht zOsh#$*e^vTGS|Z3J31u&$t-IsH)1*uU}E6=`xt&NyWdLs?C{ysg-`xe(lZwI`<7*e z#6UgC7+)(7%J9LF%Ty><*0 zN%-j6G3!lus_~NC8Z4K3ZUev4jyNfm18Vt5Z@yl)i@Y$4eg}Si*l#jBxJu;pST$uR9De z3^znJ^|IY_Xz$9udM+Tu`=O+>^sd-m!VzB9Ydxg3*H2a5-Y4(&KhyRJvl!@mK#k6a zhql%+Z6hzbolceI>HU4*n^V|w@gti|XUl2WR=2MV0@~8Phj?YnW1Ize&pTA|;rpxb zu2VoW<$xmjj3&e>?oR=-42fOtmo&xJw{dBGZ#j3${krIt!PYRdnckBMA6t8a=t;g) z(}#G!&+AO+;R8^ZP|r$b@f`nkxJjLyE5^sif_*vf&Ac|yprFoHKSvlH+ORQ_STwU@ zUmV%744f0vc%8bIbr9&)r(G(g9<~C?Tb@n)otlgH?|Z?UcR~7g*Rr#4c+9_rw_|qJ64oJP75IUO)Cg=A$9)61m@7Wdvc_f*2 z*HTWrv!xW3;2ab?)p=m8eI*>DmG z8DiMog#X6Ov);qGv73@gU-~!ql4w}ldN{OqEnw9H)N z)s(k)k%pb;H+!mh_8v%o2lT*5cne`qds{TWlWq|E2*H4Q?4fymZ@_C*s$M~PM9TTa$PDwi` z(kpeR7R=*&b%Dbht-5|fT;T*Sb|0pJ>N*mStbSg3pRd*2cTlfD0Oju@SC75go;*3f zo%q~>c!z5>h1*c?kiMB1ui@U!U+)sIcaA9;Th-(k2Y|rDeF;P+SaZ~wY#!)%R;WH+ zJl0#K=9T`}BL95!*Kz=#D51}P+PuvTe(dJGDt4+GHGSR35J_APA6YR!itax|440B* znR)bm(bKQdhATpyan7K{tSc_Qh*R)Cf5qorr#`8krl##Z{tGW za-W$CWchX$Os)jptwUM(6d*pLIPBHNVAN%i*gph-8w`5i85)aQ_B1hiwkGPO~hp&bjodF>G3BqEABR zLhagKqM|1S_76*0jd!TT1rScZ^1x;b0et9Di8jhTJZt6{ay5!^;Y)t4j$&7j(ht>- zwpTd!&J0n^L|_d54WY*jO1v6C=t)k=56fYXAer>7!&V0Pqoz&`6PcH#`x*Cbv#>IE z{nm2!cK?$II35}kaAdDR`?TRA3L8hk4y3`>D4U||5Iw9T!072S392ObHtERdrK#=M z)ST=Su>{UT-($pgRQgm|hcq4V0mx*!;aib!1%}^x_z!%m@|&ic!OoUF_WQK4e{6*K z-|=r;`2SVlf1l((clfu2gOAmJ^bdyxH^lj$ey=W-?cM?AXgA-ul#df@Z#PXTKT;>~QUY9KUtLLUCz*B*9*F+7sULR0(w{F`6f9>U_ z2oi-Z0C~irY@s{^GBZr`Yet_zb9EHC!?ozTSCpovo7B)m!=|+{tcDKdjUHyUDN=lS%5+-ZlIZndYSs$x!5%7|Q6ktvu2h?uhIJ ze-rA5WZRFB5$s9zgvlOP?O}f1or$ur%eSjN6wErA(;2V*Oob~a&FRlO3g`J?hWk?sLd6kT4cW?aHGp;Jf}EfyJ+0Cpb*5Iv$pp+SEGBFSAdY>#o>pqb>J ziDS-%yU&pby*eMIkwV>08rD9rf?S=4$k&R|`vdxf_xX6bd6{#UJRke`5}K4J@Qs*o z5OQCm3t2zAkjYOaJTkeIyWD%TYvh?Q&vwOaF*F(xGg4G!1F6Wmk~JP}?A3Wp5(1GX zsceh?CyrQsg7vm#K7F^1#J(^4j<|RzOF#Gg>K7m-tF;}R9-P@#0q3rz&ONXVLYa3I zL;W63Kk^7rbOE45?M$WKK>U_lbM>~}qw~Y?hHJ6jV2@6JG83QPanyW)?~(73@nHEW zBbR(MB?pK7qiM87XI3{7Lhg$T%NP^H;LQ77?hb*uF$Hu5VDw@6e;NaVp<@ro_4kyU zJ+_xPH2MM9)`9Jg99|l?q#>)gA0$blTI@|U#j=kX0U5JPU zO(r+fEgTIz#C2AI$A^GrTY(i$a?gfYyX|;eo)#*sbwz$?5%2O0c=$?`mtK~(X>l;x z(>n5A+>X@M=~ET*Us`5terROyYvzd9?oQH_h_eSUcjp8xwG+bCbflS7iTZ1|C!;jI zBeCRt)zfuua?nxg`Xvs0(ukV% zJx}lH(~}zx>Eqd)hYL@}k9pIt=r^DI(k~5KemdNKdwqSt=BMkc+pFvA>w}DYHG%r| z{v*}LdbpV$&!hM6zpVc755IpQ4iPWy_x`EfGIwIO`S)jQkLHWpqtDGa^U`DWo4EP9 z=k1#VeH!~EBhDCcvI+|Ui4tH=*sZfkG-T#rbv1XZ!~0Fq+xFvL8)b|)63=s(5r0z$j?1|^4Vf@K=N}_+7cd9*>2;B?9fZo8S`~9SL56t62jcA*h^E*53S5za-_^%|^d%yNz^UeB`1@re{|zr;K>+W;>{&TMWx@RLDo_ z@6a;P2{ep%M~FwtslAoh*0l5vD7mjd1=3rVes%*8?X1X7+5X9wm#*i5{I$LB z^(jP2LoQcOX*tLg$T_qH%6o=ki6PLIDlIMZ{( z_Wo(_Se8Tz-@{BuVp|P ztZ50w+QG|NEc+!oPL=_m5+pEe~b; zfBv&3w%@=0`M-blLME^G@^K7X&iE}=%xP~bY71lU@?JoAIncg8ZpvsX>c!Bu{SblJ z5X)`XdkWnG`bxA*D1QvI=DlsV7YNlm(`oLTo;_+g)LDIdEI5)WaEs9?(@Iv|DAU3HsieQ9+v&#XpqIsUuuJXx8&6DAjmtguewum*HfM-w*F(;SrVjyq zL&3ku{l+hYkr#bX?;_FMH)Vd*(g1tMxGFs5kgzfnm!ogzie>yg{tOmMy;!veOgzr2 z+PI9BPK`%-mJx?g(U~W1V`NVw@Sy1MvaVg4|hxLuiaS zoT}cBE?3<nN(;eS@SyLQCyWYQ)?~Zv)d4VKvbGUzh zUthn*e~NAH@WYchp8JE^_>wLTq=BRk;2LMn7axYau_4rxA(`s)>Y|BWabYnbOuYjnvwVyi!Q1G+0alX2_UKc-MGrpn0BRpDS29r}~ zXvlaXV&qzYj@5r*GBLM=*k!7zv2QW;&F>qyaoJJSWi-^-@rKrGME6%dL4xpp%XcpY*@S?2m)Cnt)T&lQfm zm%30ypS0F;zbW}~RmkUy@#99=%q|a|y~%~x!C2tOPNA4Po)XDy9gCv~to#AaXNX9& z4;F9e%w%^s&Shaj{CXeePQ<1PsTSqCZ``Xh12z-TUe*)e(B7C!&Z+vdvk?v&LGcs} z)>9BzA=lRQC*uAb3%5^4;oMaudUbe1V6I&g!}F#kx5%3Xvb89-N8lA-=x0r&DVJDxcp`{;K)}ye4g&vWpz9DgWcou-2DBiz3UeU z1F)YF%3Nq&2Fo_t9vkMw?gx2yu*uIj%cw)>qveJTqPZEdyro-v74zuRtz8Y}g|NNw z@6wC<&3vm!7$Ty*=JbAlpZ7b(AK&5Iq^+Rbq&++3u_bR@<3%qZ%$#dj&cr>mY@(|d z?amQ%Ev+m%Yy&;rTo=#|#oi0tvtPL{WN~!Fhb6K;tWgK$O>-P}@A=Jd-WS=c-RbVx z?A0$`+`V|mi+l3gYj3@Haj#sRPWSZP?cWpqTs^tHCVIKOy*vH->Ga0shrVEcxE{8q z+rRsq|GahJT-25f6{gT z-7oS3@Oi(=Ps5MT56PEjmS632U-;+zw0wC&`8hsU>krI7QEUC&&r$1N{V(D0^_cgi1c|2f{3WwcWjSPLaE%Cq1Zkz}8sr*zq0I^}h{M zIJ3xYA)L8>dR74skn!Z|?OWxk9k+MYeBi&uwcnhMy`M#ubH74HxgWTEYGCyEAH8qK ztgdB0TJc%X`&;&vd;dU(7RpvxNg?K~gVFB6ZWfP9zi&5ay^-C(9KIc;o9ag$#)6 zL35f1urj=^RxL5P5o_&^-lE| z*1Mzs{}~&yMV@ifa7N47TQ&=%FKNUYf$fMJTukwM;iu?UR%8?kDGlkvc5AORc%9n< zHBkL`t^Kzf-T$vn|LsICNPkItx5ec4 zegF@f@>!gHR%f5h=CjMUlD@&WA>ZRS`1G>9uwa7PMd%7A$sLyrck!>gH7ox6c>Qpe zn_lk#)|mf)eE$2tHIvV;V*2{ZPU4@4#qepS`oux-S$NO(FK7Pn`#q0~yvxEviJud0 z9V6RCB%JM^lDG291fv5dMo4f8`8M(t*00$T@U7pEYme9O3M9(=Lrb@B$Zw6gP_(bj zPZu%r_my#VOrXB;A~^E_UF5b9j(jr^y~tqUYs7Wm7Wuvk@0fdg7d?CnzP-Oil|TJ{ zMQ!~2GsyO7A^cn3>Aykxw^A~I9_VIFu1eYQ&Bd<^ZLhr21O;I3cT+Lx)h8m7}XhHsa7|7|J0Oa+SpsCvJ)=Tg! zNB`F_rRNy64thqm>663>6r&DIg?Cgv!aEp{j0SfOd+!|(yH%CP2~%bayj<@y+UW7U z_nR$O%q!HJ1+9U338#^UKHB?pCxMQ@X1#z2-b3$2ZvTK}!7QBZE2tJsDkfy&ON~o(JfLTIm6%-d5Oa2eESkbyfc~Hw0#loUe~AT z_b0<8n6K;LWTgA!$>v9wlZzc+W4lz@jb}Qt?p5)uQVMdvD}Tr|%$FLV4ST|}Nc7Ir z5q3hv-DQR>^=Tw`yhuF{)bj=jE+HR{yg(4=0rZ48a6Md|aXpuQF(1v%DjVc8sV-yw zKzYoZHru^RYBQDvzx?}zxVfsYEOJ|jtf}?P0{;GMIoci*AK`70+VNl@?*qT}etc=~ zXF=t?-!B9{x-h~6e0%O!Nqoyj5yDPisZj|iH*d|b3B;abH_v9GY(0549{r#>Q zThIA!Uo!&^o&B4ACHFeVFP2!#4IGheC_>+V5-d_jq6k%Pj9>rB)LVEVs%9~g;y9P! z=7R}zS4h9P2ctO_O%adTsZMTVMjw|=*EwB5S@q z>?%C&AJELLzjZv8+BbN0-bV?pU!ZyCfoS7F*r2=aQ~7oP*+J1ZTpR~#2;*$e%}k4o zV0hsAk>i)SCE{uUE>}l9Qaivv&cor$-4E8?39De^E39m%LN)%u_Nvc*u16jz55nf$ ztjJwt_1w_REz6GuLG(HwG>4ftQ7OK2y}VinL39UqG{<-}m_zu~*4H$lpWx%krf3Uz z5#N=kn9yt3i0cN{kR;fja`in)3hxvkZ+zc9<%CF`!&tT~a9X8H94?}E(yH0^ywsXD z<&1D6f zb{UZZ|2&4V=ud6@MUDSe%LC%f?-VWiUqO%Q_b`J0ZASXv9Qd#O<&2;I?hF6h8tVHV zD&=$EBq{HIz$*Ofzi9&eDx*B7LkYi_uE~Gw%U%JwRPhgd6rY^4POQ^*KkYPfRYoxZ z6&K_rq&UUa&By@MX0C4upk2a~A*B6UryAd$tGD8!156qsFEV(w5|U1H*G~$&d2_Cd z&5y#l+*#lsj+o>vv8|;oFLn0P^`WJyfbE%E@WZQzDt@}B+4yuB=zMX@7x4@vi5$JZ zy7DLMjRyd-d*2_hkUJV!b&h-AOug@5wZ)lMNEut8nXCYkE%?@QA^4HTvCx`$hL(rk zck2C*{swL|_(X}`egTSy2Uh{#|5pp)ZQ&Qim|?Q6jz!B9b?#ax>S-MNVHJnJzZo>^ z0pI+(IdE#+)%9YZFPeJackSI=-$Z)r@+Z;sX(cLLiN+MM3S1I7Y;%MGGH4M|F}pt{ zJE_~zdog?J`)|GDFtRDZduDuqanyUvcZ&;Kun8M0P&|VzInKng;J`z-gRG4eL>mFb z>242vvm`}CN=~|SxZF1Q2E^~ft`_!>e;NLp|GLA! zhR>UWX9AojdBaav%=)Oylgl&5pAm{u(5F{&U)Hbdlc#FE&XT_~Kp z2Kq3oiLA&+$-rF=tTUzz@vWWUp-MU7%L*w6@^7_(HqUG`5b>?ydT(K|(7weKkKXU< z9f7S+zVmC;{d{i$B1LVh@eUF3*SPr`=^ds%HxMZv7i}Qd#Rdh({+`{P#Vr4^2Kbq1 zKQ#EGn(wWa{-WVG+}+Io@r{3*1j~}!GTlXpE76P5Yy-(dmu;RqGw?yHh#*?^M|GaM zJ$mQwJoWvz-iJpLzGudvjiIGg6Fsw9f`=CD5@0=pEjiA_dIVsm(d{5}u!6(7jc@CS z?cI^>+IMHCQ;I{>i<)n8q&T=S){1Y6dSIXQ?wobi?Bc>B!JnesAoOnP_iZEAURs^5 zxlU`GBf+FsQ!CsR;$=V^Q9PQBBE4EkvCRYYmTW&n=9*HSxtQ!{-K;>&;KaA6`{O+M z@Tk=|-yErSEDAwuG2bmNop>ZKk1_;=4e?&)C3VVUU6#=WE>!oD$CrpKkBzCu z<4ZUu$K&8+pY^xU_PPiAR>nuqNc(tN-edBYPOeRcC&r9~3`;tJ#cz-W1p4`55kMtR zuj1Ag<<%sMb^}o&OJobU0YtJ5$5?5iXvnF~gDnRE`Yz^_`d;(K4se9NRS&eWwKU1( z;8})7xIYQ-VW2673zs5~-g&rxU0w6X>`&HZzP)*P&9?D=Y%1@i1^!+p>(X6672?`< zO+9+rVxC5M_#+b(rl0CKkN1xL5h1P*aDVS2^}K0%SBexq?0+495=@WE{q~5+G&mW$ zMfR1ozW3)%Sf7e@pn1GF%!teD^sJdHdAlR!379k^wDWBIaoGF_6Cw?{x^}$>K<{)l zEx+@Tk}jF-T&B~U;RN~E)Egk=EO@0$i&Mt8Zhh;}=U=T)c5Bd5oxr1$5ZJoUS0Qe6 zSMJ7@s3PmtLOc=uXFR&6+3cjrOWqgm(W!b>hh_MxO1pKxPc7NV_?trR<$9rlzYY!O z2FOt4_e8MH;&S)pW-u0choeh+yiNE{!roHV#>iXMw{1Pylr5;oAv{cn`q`i zmPTDx%+?nLE<80C~j@eWxq>9nmt-^kCg@El?YGNd~#Xn{3}QUjyX z>3#OTJ0;lU);vd8js%p*5cp(&To9ia%c)SKmLG)X9;;Dl(C($=y#vB-n^tmb=~RR~ zhWk!0<|HTLp0f)PRE5h|zipwNGve5-(N3(@tpzgx>=gPf92|+0q&!sqiJwiUINjoq zu%6J?#5jfd(>=)#Yb9^{YKUxWYiW2|^CIwdI|tV+w};NbyaN4$e0H`c3jDy?actWg zM28Lpor_?IshFLF3A(OF|C~KP~q` z!%O=9$_3SEziQX1pr6oXiJ!dr`>W=r$c~({+K2M|@Bh;i`N>n8Zp^W{yp zh2|#wXzhfd<%a#nQ({_rx8vrZI702GA#wLEh*AX2b$d1NBm(iN!aG+lp;l+_u;euG zikS4tLG=Jba-9zq#Ssrf{hzx5zso0TicqP$bf78f#-HOThQZ!Ca`pnVcKAfFI=gqUdD9TW4Ol5qF1o!5bvy z!|ZDYJ>~GEbIND|=<$Fb;*xN8h_9~g&BdIkGvm7)8(w?-pxfv9!sN}H&w-*sk;`H- z&YH7PoU_j~@!_aghbI^VjS=pscG#jhx@I*vP8T4JOn#S7U)&7NH1g#`Go$fN3hD$yr8MWvWGlaF*7|Dit5u(uB0_P*ao^6ee!&u z=3e@zx$iYcqsI2GyL(-3x%I?B1?z%h??ni=jZ6j9C?JhRt1OfOaa^l|t9N>AA|NtS z)2=_HcO=YU5n^vp=h3|e!qLMU0$U5LF8nU|xbvhJs!P8(vrzkn(9wwIM($y{`-XG` z=o`&DNE}l=6$uOWO`t%qI~v|j?p1k<|0cL&zG0jol zX=Xi{C?%El)RhU^czwrUgPo(jNk^$EWA|>*`OCF#g_@P4cW!Kl9*$ZBIWc7<<4DJW z(*t$WEzOt?-#I4{0@+03v+{AQBuG3I1{_~(RIUuDE_52~T*r$bR|XKKDceX<7{-og zwXNOA7Pe8fvoqYVuZ94i<9*2j3k{vhk!a>|2hCgLpnOc#?Pvw(iqGk*`SW=W@F;$ z@SM+wBf)3B6CY;;9)!9GKF)HZFz|u~*CQ}DW!!YSw~0Cf&B>7dEZ>Qe=Mf_XjChjz zQQ%Fo-O(7{PJx?e_`@~S(o!uo96+Up&PcvQEco?sz6A=@TD>K3*51O`H2mpo-nEb! z96*uYPKZ5ld5INF?3u=;Os1`%+X+DKNokZyZz?N-X}MEG?aJ5Fa^<|oI~?g%)(*-$ z7K$kQ9YMz#8U=Xce6@Ljj_;=jcifY=`=v4TxVqzO8~c#)?3vJ;@>fE zaA#k5{C4;`@vFmdqDuTZ99%tCur7j-%hRMm9rvZV2*nY%YXfEpMj;ocs3!_{*$l@Q zpSf~cRZ8iTq`->s!1d_k^eb%TQp%4{?Zm@#$ekbZ^vl2{y^drbV!d#*u`zf{HpJt2 zFqpa~bMp>EBE6egCByd!pxl52Pm)sDC{WJ})oEImd#Pz4OnsI!UP3Q@e&3m&RZrN1 zpXiHN?QaJq z^8@|c5StEeuVVZTeijmCGuCy64*CWezVR|(Knzr@JOGx9ni}&gq}mwDlq_%6%dwW-D0AisQw_bQvhg|dXqKVkXedW zb$N2wdz%N`Xt+bc=>c~%r0S~TtWpD+IKfM_4hmtzMHMW1XL!`!Ll(<*+*H7uRI4~u zI*-rDU6<~#@NVlBp#}HGm0J=oLhLYEWP7gr7tRvj7)OUAFSkw?9lFVttgsa2nLNgz_+^&LKh2y)~=8CF0*hFa6z_3`BT-!)~9#hvymEaPP$aV4e5#UidNr`$dVj{ z@AWO&LO6WhSjn?~Iq3&xOY?q6emnE6>t^q`&)M2EoPb}jlvIyw1N7zkKlYwL1Hi-i zHUz)rbP)X*Nc;GSygG^MEDWf|_)$DJ9t@bJU=(g6YV!}zMtoEBkovn*m4qXC$`$)(9l z+?73>U*T`K##$ykcu|r28@Me=940iz7~<5<)(~ylK`JAO0A^h5HB&Rkb_IIf-XYNr za{N?qlmxh2BHB{$x0wumTQHlgmX_{lLDeK~a5xnso{VBqO|y3~-o2}@zxt&S3Iyf9 zzdq#rix?-zpSpcw2H55$Vzs9>Yal7f|>O$Q=V|HV$eMT)Z^$aDwBstH0W@$D(b~QUs(jg6ZfW& znZ1Jw;9{GRYLbhtJ$VsG!gcF48IiGbDHLU)Y(Ys7nIXsDq(0 zx}TVI4Cu^^C~N@VE%Oa;9^CStHiSDfTdw1xnMFA3fzo|BpAOXK;d~O@Y*lhvJwi$| zmX=~sKpTMAdsZ#F_hNG#N=>+9@&Rg^3jX^bHv5dge!4A|S^`omm zKFDyQ1r8T98~l#G1RRLSic~sUeba!M_udH6iv$yM%e)E*bKH|z1iz?RJj_x!yhL(a zGF0UI$8{Q^Xbe+oZ(&inj*~jTUh%es0S-jYH8d#$Li#*+?i*)Q+9d~xo$iqrz_@4U zi)vv};jJIQ*{({*tvm8t#&G+RgnQY#2c8#R6Pl5(dxqyb!5d00^a*P1nH?ZvzOlnt z>Z6#dV??pXJtEgl;4XPo#OWg$d#yuzdrG!Cfo4a|8Lz+OBJB6 zN$5rG7KL0aW}tcWrGjq<-I@1I><#;ff+cjt;6&yW8IWD)r^4k~7qv<_8W;)viacthwC!Caw+oRR1iM?yn;$h-@(L5Q)NmA>2mQXCUj95Z z5O`}Ic6VK<10qLrfcVDIN{+ZOKBZl*GR)ufj<*E1ZXeR5IduMa4wXUrH^RS(5bEln z!=W#H_jM?&nVwLG=bAO_zrm`bNB8~s1d~a}>ElxE!~R0wRv_~@Qv}%>JHOE1!_M8! zGex4wm9(9^Ck)jqE%?2<3EXi;+mAJ`_r(R-iRP@YZ=M$K|A)N68R1 zt}n^3Z331hvxmfzR}7)KSEI{i`U|6Uk(;+t%3bE=YE>k3n*r%>=SrXZ|JdjD9r>7} z&U_`jl`DJ^oBJt0SbQlqe1t5IpH;uh?_yBi{3$Q>xAe>mndX(O0LkE)25D>0N2}mw zV)Qb9J+F*~gMu)->%mJA{&bBXp9xQmr6I_!0fCoQ!k+f<)1*u>W8w|-z??^)BFvgB zlg7g_$rKr>zG@Q_rGHfw8p5dAG}aRp^AYws6l84*->Y0G>-ygU`g_1*w6_7WwpnfZc@DuRNIE17mvLevtd z3hN&Ngs?=cyDtgq>ns_yP!)zaAE%1ny0t5)YWXGrH|+|SHV0P zcF1eLZSX3(7y!XjVUa9vS%Kio0{>%DV6v)y_ z`qg{hDl(y=0Vm_F3XOQtOyFTUod#NVduRLqqW7zw!p!DRueSv?>U_jo@H)b8B1}_X|R}vDr>Vo(Acj@n7+sL#6V&yF7Q%u#Bae&CZ(k;X8w|9T+!- zDJNXKcx){vwa_{PVE&T&k?L2!!=c(Qy&2>>kXu1?{zZPm*8j{!%IY!yV4=n4n~7>j z<9U-D*3FVh=p9?}t=2mo(;NZJ)tqCujGH_AW1zco>|~_Fdd>23I{OrdQkFek&}b1YshbkbCtVcxm7|ZA`QRs9A;e-N-ziP6Z8&gO=0hI z04}kfjH3JB-)RERrkoW@!?STRs3B^03v~cXJ13LXdLokSS(;uP3^u1Uv}U{!#pr=U zssn~{gL8-Ku^oWU@5Fggc0k1Km@SwF&>8$L0co0?gWY2!6Qi>ZNHCjn#8YO{-f<{< z3)cL``dJjnl9l|-Td#evrl6q#C*v(!Z$umNAj_GsKxnt&dgnOQyLz@aw~)6W-?aIZ z0B6u5X+CfzYC*dYY6}d$h-ZN}08E1z)UvpS&>G|+Mn*6XE*1RUtHUW7tqH$_??%p2 z58W60&4TX2PLpku`SJ3Of@i)}F!Uz7z0eF1d293##4x4tM&URBis+msBf2Vlj@h1y zwujQ!qU@<-$;=Hqr0GlTrr~ zYseUay#luu#C(K7*hu^vB;0X$Q8Md+Kv@7H@)VKE=KD)6Xo_;an<;F?bhof`sctht zGhsbbTvRz!qtz02;1kg}jOZUt-XUe=zJk0Z&)Yao4GTPlJqD-?Z5JH8Fm*YQI@Cf) z7^aAxf&#BDY=p^+O4ralG1(T=66rG0?Qz2)0LZ=E}tw#6>&So*KOG zDZri5bK+87t10IuBh&^A&R!24nj?f~KpG-MXzgIw5ExnmYS1u-=#iMi^+5sxC#Jmw zk#gxa{k|lG+^p{nv5@*>`ECck$!p~BEg5f#*WwzG=jC6 zT4^c98MKdPq=6&&i}Esb#U(X`H>Xt`%`dXY zqkaF(gD=vxz4y9%p0UP=u;pZl9Ern|N++|ppf>MkGPlV}wvBqqK^p;NE;2eH4Wenp zrH!>wvm;Er_CR#DQS7%OUq1`uh5hD!@}KTm^QG}xCi2SXnP}E06=M^IS{jIR(p+c; z9Wtr)7ZS2CAieW?e+F6;R(_DU?zY1~5JYny%vW+27(w6tCQ6F3B;&!kIZD^2Eh$D6 z>cN9}QkxwL+~?u0i$Zf)u1(gPkF{i}Wg@|p%vv|>qj6kB1#6YutGck(R*tXyCFp@5 zjV+~3Z(oxU*^91&cn6}g8Zi=uK?&DUAiMO4Y;2&IGlNXf`>J@!4m0DZ){q8f=6Ar2 z+gN~*rSlv?W?LYiSjdShC}gf#@D)a+bs_DcFjz|(W@X?-0&h%7rvK4UcKztp^wAh{ zR>JankljG}_c5-jPVi_<6`c337-8dW9Kzh1cER01&na)EFZnSAq@(}{1>SqM4puHb z9wKn#c4UVPP6jU<;%k6`@Y@En5B7MNW%14uQfTD8KUm&c8h$6WKe#ruH7=@z|6Lp~c5!yqTmIdnG zb;e|Y^$B{rMgDJPKT*`&lxs`z$Cif9UeO2ThlRS{#@?YoZSU-&M=<{?#fVdc7CtP* z(1)9dD$dZ~Gmr$O_smfz#?|Kyim;k*B72J=UlpZ7g)0Tj-qFOMZmVgj_zxRGdxP-m zOQjvq;wJ0Bjr*z*j$AQAPKMCXWsi^FQ1B3v-dyw68#8|p*&6XSgORlE2m@4*tYl^I zfinIS39i&QPp5W|VebV>C8ZSTt7q&)msGFh5&?O8$5Ta}F(OeC(MzEeagw_r*?DJd zurHrbw+W}Wc~u4PaMq|rh|4jafG ztxj>bZ2`wE04lIzN-I!jBsi(FSOxpiNcUV65t9vqYu}K*PK)cHlEraPI#L4fjMD#1 z%Mp0I1jV`Gv&fX>`)JU!x&(aHK)$_8B9y@G=iGqe&-1aAfo-aTYD+9_L1q-+l(RHR z@;rHBQlTShQiaLcQSV@W+jIYSPsVB|HfL)vFqJnqNF(27q?uuGX3KU+F?ivIv>s&F zMYT3WX8=bw-SH5s(}xGZu%ZM~oGA9qvih{-NimZ9tCf6EWrq9-rrZ%&2rJU8$y_@9 zaoRi1r@BXF_U1vXw!keZ9uQ=|IBcqG0>Tla4T^2zOv?Ca)z0$QiQZ>GI_T`u)8I|z zv;^|UXa&s)+=*JyQRGnY0Rd+;mk53Y*D;zV6dw^1qXj`6D(wI*Zm@zK>YMMto|#;9 z+R=b3d$7l1WW?!iz%)rMtNoyl9XsW^lf{Gwxm#N>*vKS<50vu9NU)^Kt^Jjme!66> z$4jUJptw&vN*7Rl4O#n00P;l)uNM5?rvhz~?%fcr7(qE=6(qrS6e*~^kxS@I6>7Cr zj`Qe1l7s>pUYa@NNzJ_@ELGE@;tiXU-0AY|xblYB;^$4A^EhOmI&DLk2I8p97H~l+ z{T70>5a7TODbYOjU3wngIkn25Dq5Yr|8I=svchtw4qJ0(T9<-b)Hu;gVs=o3a4^cD zQxV&Zq2VB1P;W6uKzd_SnkQT&c=)D_E=LLvk?cZ@CvS*!Y7|Z+GDsfT#4%S7n@SmY8_F15cPSfywlu~wiUd^y5V>DP(frz6K4hla5 ziXQ4WlfLu?R+1J2Wa+*aw7<6C3@iy-8WEnQU0V=9^slElL1#9RXG zi8&VFC-oTFZxeae7`ClIxnV|6AIyS*+nx2$HL=yd6dc^9!c$8j9sc}L!_c4yhp9|`BCcKy6#1=Ozc z#*z_OA3F5gQwdle4UmjcbLAH9^{LbK62_;^&QJTGZ_5ed*0p(^>Y(tYxe%iPc6sk7 za~+%?rXlRQJk7jFVBQy|@b`r@&ux>q{HVQZ<(=g&k@p1a7{e;v-i>S>+cXp8UZ!j# z6f%05;iSytvN1N?dwH&7V&0(jg_PiM2E8{{(k1|Qn(PCRFETav8}vE<%m6$kc;z#H z4SA^^My1w6LkhekXzXIFp&o0#>YltqPyBqp#a%B?J%Oj1khOsBwWTsKNeMwb*9(@P~`@#;_}NU?Ji(6ydHs7U~Whw|n!NDO^S zM33vQE~zNhu_A%=fFn9ufJCIo|+zGM_U0KA)PIHvL+T&EVb@{f>`nYW9 z*%|JErW|v~(pJB|=11r<;@M`tm5iGq5lFnUosdwZ(P#Q4#$30MNyQPoe}?dh698lW#(Pr{+2xS|oGS$wOx9 z)sc5XJGwib*5;VT*7(vTQu|B*<)C_pm&e5R12>QoWHiscVtCs!&>q9Dw@;0>E|U2V z$K)5H_Ks*(3l4`Q?6&H+4SrVV2#4Moanrk;v`43+6n+-eCmja_LQf?UEASZ_y+C!yj8wIKu5&FYG)GDU1_E){ABm zlfBfi%q?-9rn|C*aZMW5*_+#V-8wKfvq&>xoKBArd^0H(o?z&j?p@%myE|<)Pr>YV zb^1GhDrE4b8tRRvTaFx3y7>4~^$y-!cr@dKX*={aIXefwIkX*UFxq;fFWKldQlXcm zcS-I*r}QRPP@wnD55Kf%adcMz9Xa(eRr`{8TJ(--Y#Lv5 z38_74!vlx>9?_bJP6Hc2E)FP^BkrU@2;O!o86-1gXGShTW~qPcQrx$2qb0SfMVmts z4fbxs>^XAZnZVv@$W!kJHMJeF=e8yE!6!V$v;>!kFr}qHhE5^rQ5CKz4u`nMBgF?W6~&9 zW7BaUC0 zb2z%PsR6j*r^S>-pu!b`23ewFCg(fE9vVQ(S9uOa2{kttF3Y-z9C3*DMg&B+J4Nk= zk;8XnV{865Biqd@@jcIogHTN>TkF(;%iiK5z?*TJZw~sS%PG#J@PZ1)@AJHz;@l32 zdDRvvnpHGDlS*H#h-3^_DjS8TlyRiHC@g4KEw?6A|odqM60>)j8lU;_F3eIES!;f zW(-6~e5W6T5_VcpOOllkH+gPi4}Dz5h%8fJ#Nf0EUyn?J(-ivUwZ2_W-+ntn%4PJP zw;5|JGz_76aM5Q*(%G;JgMf-G5G}HS^4q`Q(@0VcAagC9+-+}>N%v|EF1q0FWk~Ba zvb@k;A;PIvHih3*kL5ek`N(?(b}tlFDPVCe2BDm-a&Iog-NYa|dWpa8h=`@cZz4NZ zhir$odF7~6ZE+g~>Q{>3ep(g(8!iUB!t0uNd;P@V!&Sim=%_okR4IS9|9o!DuoqQ$ z1IUTl)OCL$#k9DY&|h;=?GSN?&M?zOC!^d-AbQ8q9(DQ-FTR};>J(P9L5mguvWNYT z;r`L}#f}d9vG~Y4bf9ly7L9!L9DL;C(cp{nBu4g>he6He(s@ws$?!INdL+DRw(I*b z8uq&%Nv?|GIRd8nY>0Q6<=BkDZ*84j#Y`sY=f964T_1Ngd z13vo8RFk7efEquAm~_~Oa}3Qzw3+ide0KAGSl#sO>V*eXk_M`RSo64D&?4&zm}9%Ip0 zw1)0aQegK>qFEI+H_VC&h5ajc7SD~LjF=AaZ+)CK=riJ9W;i}mt zXUweaqSKXQmHdzDTUr>;{EmK8e97IJ6yE|W&%Y=PFUW(gR!Ih1zz@OhFcqye!JA}S zTf#_lcMPYIP&w0GPuIY|szpaXlf;<1TOxpHI0M;vy9!-!!!2z93^5D#JnZJB#ckUq z#nsv-6CHDdCN67kq@M97yi1bUSwRm-M+m^O7tkSM06xAQD-%fXZQrp9CT8+(TJ_t!9p(*B6=9 zh`ZP!q(kq%6rhuKht5_73@@APCA|*?336MN6k+OJ%3KEe0q4LlbVxphcgRhPf~_13 zv@kO*kg)%g!ta82JHMl&5T}D!0rye9jKD?|4nsm!&>E00it_cmM zzeVo$)2YU#GYNDI6owrMX7u#XlKFz)TsdD%srO7EojQLbiT3D3DF`@3z8gz1i8`mu z@9E>25vLW)rsv(Ms~u?nk%w~bE|OcDxZWLZr1hp8d9mCyR9nHIk zq>|h5^au_PdkPy4(kFA>rYAysBs7EAP4va4h}jnL)E@irJIV$u4($@z*aQ~}Gxk8O z!}S<6?Lq2Ily&sbMZrS*wo5t9MY5=O0wZgGzrpf4pfUNN0DM*s1LSHK%^X~^KO>W^ zXEAtpt|dF$d(lVvw#e=sbdPX%$Q`tS12gezEE#0Yv`FFiYPddqCt6noJ?l%*)Z~qe z@4?vJGooQ7S{HB((S*e#RG(uZ6rYH+6ewLehGd9z+&km3!g2w?_;HTQZj~yqUgr{L z&}tWcC*sraiLJ_k6%Y}srLi1LZRZ}m8<_R*yo%`2{a!+_>*Mrw(vqvCRh$jFZ zS+d9P@=_og0<3+k8ee0Jgx>{C2EPk^-~yHVNQn~{5qc_fT4Twbdjtzabh)ARBI?ym z3k9=s$bjg>38Jygc(9CjQ;=vB;&jKNC_vZ|fwM(L7?0;i?T5@Alx5PF*pFFsbAE3i z@Ka$&4UcINbn8Psw(6oM5{2<^KPItnQ-f7$)Z_bW*<@AzHvJVD6sJr*;`gO#i*gwy z#0KD9BLKr=4h5GJ0D}xsd=S!Y^K!e#iPoItT0-ea+e#?;!DB9x>uCg>N|FiBE79(E zQy3e~PQvA!_hO*I)Pt@Uxx3W-Uie)V0r%;cgIa`Eh|Th+Bna+f2irl~!w(%wrxx>} zto3xUqTM*phCF$1cro|Ae{WY@!pV`@+Z~#{J2a!V;9J+<2i4c8$|iH;%~KR$cnI95 zN*FXO>4<&QdRzCcV(nsgP5Y9GqGgeut-IG`_|U+q0BBvLjid2rW0J&uuE+7kZhwxf zvMdPPQn7nbynKJ_PjjNy6Ke`UP! zdH0$w^5$2OoY^RlxaYGqlQe!BF^sJwqLB$BX+1G|so8pasVBwFk^zPuPj$YtNYj1q zAmB&}Bi8TS58GY-X$mZ zZ_F%@F2r@y>4j3DQj6ar8yeewa`EuY&K!Wot$%{nj@N=yvL9;)a)e9rpmT7L`|4oY z6zuWCYKEFE`e$3H;AgH=>*22O2A=5fuC7@34=}=of%{ zo%K!NXlUr~H74#kLH@Xx1N4QBR<1;Ra9a7lJ6i>j_~j$|h_#K6;~J5vaSs5qepyl@ zA_%6SigI9d!q4qPXrJ%}*LwxDdwxLlOHGa!ExCXk+4#P1?O@42(~h6MfNZwJD(!kE zge)%%0P4U`=E>c!=DQY?*#wrJf?(~WON$1jdM$QEcZO7KURVI@u*q`mIF*l^~h zPfuZEo{X%^AT!p0syOGLo^NuSj9xf?$!g-D_mP~Ra__(scz9_k>({@%dv&K`8Max@ zKl~}nz}^KTZLi+jv)hKR4^tgy%iSXXxk{+sHC&E%D7<4Kl7ozY1fU&_pS(;^|+oFQSrs?h50l;uX}^~+}OM|#M!M_ zeFTl-?qPKVZit}=H12rdYVbYZi5pf2TBeFoZsg0Hh@+xHn1h>#^99p{l0>n_>B`c3KhL{Trg4U)~<5ZMBQM+@0n zmVpKcG#u>($PVohM3n*2I1%JPW(9#x)Bp7tK(PR$nekJ7`}Cqk2SkZ&EP)3v4Q0*V zkJZ@N?E&AKRvmf3AHp=A?{-a2=@tsK#l$g_mo( zEqa?Z-KM{lR5C)@z_dG#IcStVc%FzS1107%KV2A)#7Pc!%-dsZfv2%#juSHv23}#v34+f6S zxn7#}>ElSZXNiyQ^!R2LF5eWCqb>?gz|f4%g$8sZbtaBkTvI!vojrtTVtE;VhBMS= zCNP_aOh4*-<*^rFI$3>B+k1*aSF(-HoDnz%eyb$l3hbUnLZC%;auapkSuSctBGWJ% z>m-hBO3nPShv$i&@Q%K$`QmtsmwP#VZ*_+tYDQSe`AAzo9FQwK)IwKxY0VAUt|scO z8_L`VqllkK@Y3LPwY(=mvCSsaiz?1U3G&OF(f?U=hq0#>Q*a$^j z$R54|95>A&?(_K3hFL=TsIyZyiey)rE5#-g@-Al#RW60A@1DH(bRgTZRFgKs(6s2)3#{s*)nJuSB_rK#BRry_4MG_*LlR_)wJeP=Hcia>C6+`nXQ18_s$H-V0VF}=PRaYuAH{r zdxxo)DrcXtv>i7zFdHS8XUC&{jf-y`Ggn8VC?p}jEE)wKBxPy4(WRg|Kd7h#(KhB{LpB5Oj*AcZ(=fj-NqBxJEBn*}Qv zeGBpcw-dr|?*IDE>Egx;+PX+E*i`k40z9Y7`y_e5TeJ70dOsA8IgU9G>3c?Y9@%X= zUb8IX0ZX+2OC!~?=41jb9KN~fqJz8N^3s0OhObG7puf=X?s5pL(FQ@( zRFZ0e%F&+!GJgnSb}&~k=tZ|4j^Hn(-VC{+SyvAYpx!XK8s1`(xfbLI+U}7ifjx)@vk)?G zK=d@4E5gM=1fXk-w~n|x5@;}!17439RNZO(J(o6VYnkV7reG&$Ul zznG308rtkO#VB#p}2@7W{UoaPm)B8YWu{b1li?R3^*%nIpuplrLftZrf=WB8I#NIGL9-^>inh*?*_DFGJQLBXP z9)=AJT!gv%$hZ%CBghth2a|+(ax<`wMu^8{Qc*5K9Yxq0QLFXcz>>5WmXudpFd7*Y zIn{GXMkvAsZ|>M{ifcxzXHMTa{KnY$R5|w!=E@lWcMON4T;?|)_jXK_GyILf9Ok`| z>yzdvk0X1kL_lu3!ZkGaZ7F)&)=ptPF@{KuI03BVF?CroDKNM6JSM{iv~j!9&Y?q+ z+Bj@fx}bg0Jq|HlvvkNkSj2;*o7=#3W*#v>B!PJXEH$zDloc(^iAJWm<@p+EOb)n*7Yg5g6bDAvQsE!tym?1R+o zRug2{o)o^n;M=)R54zH``1B>7@gSx6o!@CZ(57GI-+ACU9xtmr(|7(9E4}U0X!eH# z_BfB!<_8UoS!DI1bw!8GuH80e!peI|q7@VSJtN__xrhxf@;+@ue4H$f2gQbM0@D?4 z18`qLCusKQe;=28*Y$L+^ z%@w#g9A$C^k^+#6(=r0;%a{o#W^2dm0TKmczaqEGc&>jRRusW~HcC9-V%A0ifSHsb z8Y&6QxfGL0#_qJyI5f|kC)YT+2<_Lw3Nel0a^-*oA6<{Ei@^K5`iPW!3nm2}W1rNA zSg#L*bjR^( z%h$ak`J&S=;psg9sBwS>;LCC(YwxIkx;m4mQeOZ2135WboFu2eUJfd=Mlw7SV7ZEB z%jJSS&zv+i)YRmAI0$a#Z)}So;l&Jf2y$iaQ+O{m4s!1$@qQG%P0VqJQkRY{jU7Tf zdY6TV2*2pvo||iv$eM@kzjL6cKlUzzZ5K}OEl4GB1r)Hg5{sT+QghuC;vNx_2f0-l zB7q*+5%bdX6R21pD*!JoJqyWZ*+r?|Z!bZw|5#Rd@pIYb&wkBUs0(JsQ)fJjTnV(c zFDl%YvTGrqxJ&jQ9<-+1iiFc?2Bf%r5EaU{GEn8+(3du%B+-3$MxQ7!r5Q-R7l_?T z_-hDZcj~YQIIDw(D6gTBuXlLU@YE_=+XfyNV({BsP`6RvYcpOFVXdzo)tl)AQz8NSUIq>%MB3hm|#Ernw-wfhg4x^=y z8x?d(MN^%`ck%Kk;J|AEKFrrBwaF{0k?PwTgg9W~1N{TXzD1QpaXpcgDqMb_AO@!= z=UeWbh)IHuKWMqt`-=V;)8;v%(1LgRaDF5bU1+9zR}M&Uyp^c)>D~b&4SuO84-yJ? z>72X<>K~9_W2|^UwWuMW0`NQWe&W;tDRTsCE`>cfO5mLAm$Vf^8WV`2j)ELkU8zLa zdcL+x{1S`4dj`!eZ6CxnvIGhV@kF_3;Yq*Hd+^^Fl9n|OwjW&d^v&MW%yZljLP074 zD*z1mmi)aRUs8Z>1oyzQG0TV$3vyvxf#0P7$JrN7=}3}UYJrU0bL09qzfTsZ5w z#beWXOJ|S@w*j~*5aBKU9;O`tHpt&B8~`T3TGjZxxGBVY(rn8FC4$9+8s|tL&4}Gm z3=(qS?a~p#?}E&Oz94lRep8`)12~>6c~YP+>MnqV1GYu`Sf}<8Eifx;YpP9$a=Q%V z@KE%?$23_nL%}^LJ9#+gL`6HuT;ayD zqwhN{g$=Pl)$n}{4Zyh2;%L2STjTLqN9MVBIKxm`NWWa@0i`p9UMW_Wn}v0)<*BcO zv2{fr=V_XEQuKl4YQxxqob`m$qK1x8Jyl;4mk}4#B=IR&uZKa>Z&zK6mrl%C#QsGLw#vrC2! z^)(6I0jI}qOFFN>X-fo5fxy66J9!rw&&H_vtT)`qtvvV{$c5m+cP;=&w`Yv*v-xoD zI|xBT;CBUo5X#Tc_c^?A@ZIFQiNd!dmPtw3H`V{PJ)#oo0cGKDUlP_%Qs3A3zZFmv zX{YbA>W|X)m>kyVHN)d(%f4jf9745-Kr~w$(33oiRe^*jrrr}Dn0T;D_fCqA)l9G( zpqhZy~$N9SH8eg;gHF)-EG{w9plA2-&jXU8TPagE$zKXc%1Q~g!$;SiOQ=U(8 zYKRjS69Q9NUL%(~SUzCiHw@F|xkjh)ig@sS-J&0^x6<+r!_dACGgu#9xL5ZYyb21n zr`eJzuzl3+q}!h z=;Ns3eU*`L;iqxtDZWEiXvjl(pUJK-vOg!Yh1^Si^2BMcopkZf4&z~`1oW*?mvw;G*9 z$&y2(K8tEdeqJ?;Mv)wYk-w?GFxM??jP;XBeHCeaImif-yEz%TkX?#C^oN^}mSQ~y z$ccb>xOVGS8yD`&F~8j;Z>lrdB)&x&gs~19@%v5i&qZDS@l=@d#&JWmLS#=3J@6C$ zIw_|2rH~!W;YQ*Gqot(+@ZddUtG{=gu~(Bg*UWnaU^~Hy9pYSU(vgpuM_fit7flmH z#(W1j`ymyH`wrhfyLv7bl08XoHPFHJ;+Z_oG zyIs_K18HDg3K<1$8hqcs#5;bw{&?;^qIzJl*}Cf0X{+ExK>Vino*tGbc{Bd1)^6{H zjx?XF0#>*S{6YlTL>0S`PD|%Mhl6tqE>KbP9n((J^!F;}kE;Az=9wdlb>g?&?DYon zzY6}$=@j%29e)!pT|7%}Z^|BEL8>=_y;9cbU?iiP8Gl*wtw#EQb{Pb>6lU^5>pnZg zP=~MJhcZ0!r63OkSYoO2h$Gh=1K=C-SS@l7V@hi~(nf~;gAFWsvffWR+*+KE2V^6n zCYoG39k#5v4xG}?SmE@&;7QhdO)X#omQpPm{Z7=le0!Ie$2P2=;_jH9;m-Wr0O9uq z@*NHNg9B+80L)ODQplRh>=#$axl70{tqd2;l3HHAAI}9?~YQ6dEQGhSZq_^ z>Jf69<%A=tV{3$98w>B={olDL5dwX}sMGvUGbA z^ERE|N1MpM{eBmL)4p-B=1E~9&vI6Q8k8WTz(>LiG)rhfc#q6H!rI88(G3rOqpoKy zyG&lF-=aqV`yL1CMR##sZeeTscv@S1i(=O8vxd^PxeL>0b9v|5_G-Y4zq*`70!6;< zh?OHDrw{;cy+4sm^j=q@@+JMKi!COF98v|1n{b4+QYd_v2sO%}>L^@JgZMh{-HLGA z0x=gP$U-A7cB6T%8{X+0nyOWL2n8++2E`fdNC95+#|b0VPAiP3yMqC6!q_k%WT6d* zg&;0F|7@5Pu3>ZA9?M%prBPH{tgrHX^*n z(Ir}2;$YB}<_L>PQ{hhFx$1CQZs%+6ParA9on|6Z*-czQm5I$*Gr-RgH-tpKBPvG` zFj>vDz{S9Iv(He5%qx!IVa;q{`{2Ke;q#NFLEqs=w(l0&CS}nnNTCsg-v}Za-zH!@ z`uHwQlW)r<%E_ZPDyv1-|2C14@+h^>on#FiFtTXO;2^{>IbEvD4Ith)IIGB5$))wo zuKX&75Wv~+3BJO`o>G{O7 z;{&}@rF&hQc=8VXX4sA4-U3O`u>+_kmZ?eVl(+*PH%*D`NRC3MZMjMg=Jm^?IeDq5 zGqbNW7qQIjjzDu1#+OMb9itaUcEErQ2H)Xw)E#%7kQAj}y5@P%w}{6;Ek}jBL@2D! z$tsegnB;f?etczH*F5dC-sSmnk5_s879ORQxx~`%`$mSCzK(&*I6ngN=_#*9E~25} zN1n=bEf$9eRa>A{wIjzdKGEJ4;J*A~D}rCg%*}t`^r`bNXiLhzjaxbb?xBybM)EQU zZGXYSPFF7YxfaQtnFsC?$fNhsVtVtMF2U$1u#zhc{qb-u9Rv3FLx6M&!*AE_c5AHO z&Pa_*!qC$ifZ9yrawDN(rp($w*O=aLJAAsP#oG*ZGtdv{D@Mrfr)`;N&Kw6hDXdvq z@<%<+7GStbkY=VI+2f@d9|Jo*yZB{H`ThyolAbaj)nxBVn_n=w3MD4hbTY*9|O~91prkH-n1>nPqUsNEe{BV8cnzopv@JieJ{JG+ZBz?*3`}sX6SQxvMH0RK_ z?7IM?cO5PP;QHIKxh)Fw%EEN^j_L3qNhZLBg3S_(5B5d+Qy0Z~lWg-55-jGBBqq{1KQDzS zF@ZWV z5DX#IedhWTu*qzCvM-rZyt|6WOwi+(~Uy+hlwnw53JHrt9PcQsI)yB18=tb<|rnOA;(G9B0vG!tq@WrY91M_?*x zATJ@=kDvzp4qAscVmfqH?$l9f`VQb<1AMoTv0TO-} zMFI>KTZUhplFGF?C1$sGH(995OOiAyROY!=cOI@C(U8)@~Et#RN6&0mcaLsA7sur`Hw zN)s+wC@C2C%=DC*W+bHPOYln8G|*GzOpSvh?Ml2q8;RCc?PAr7w6s9+05^q1LANn( zS$J<##AypG4mLV?4xm}c6MYC-$d^U>6AbqTYc@vG1wx5Xg?#xO28TR7Qmuhp(EkZ= z=O$u-rHbE`wHOC=K6D@?eG~U|tm3)5Q!-8XvbA*(NZLE0Pe@u9oc&V~l|K)%fbLPM zJAiMBnhARao6B_G_d)TxgYT>Ot}7OhX&qWtQgXxv9IW}|h*xRtD$!ZO1gdo^yFsO` z7Hs2?4x1-tTyt}RSv>Uw4KDI9!Q?^ZuizJ?^TEmlcxy)U+uAjuUo{z-DS=b z$03H5N)T524k?&Z==j!c1l!{IOxJl`UmA|GR-bOX*Cf7+1)sE&-5o-4x01^m@VT&{ z`5`z_K+PX^AJL;7=P%-BCL>x$wYV@mj)U<|OYgk*2=cBSZ3UT*`FK(DIlLn;puc*J6MGF8dB!tPT|tcv+RPD>ZF|H6 z!|^famY?o#6Tk;u>4o*!+rAPEMfGg2n!_0T-PgSB>D?wEPwjM!YFR4fujiF%x|B7W zW$q_c3h!-m7E@>X+PYrvM!#bSnmhF0yX+lmW z(YSXDPP(@d50i*!6E$2w-P>&E$?Lth=hi*`+BMhwwWq7`rqB7Dy348EtO) z*8w}2lZ%6ZTGAEm9xaKqv#mDJy@yvJmm#_LFGoC?g(o8PzS>N6!To}!@QL2l2tGVT zTyR8D=Pv`&*$dEtnJNYZHl&;rQlpyN-#JPRML=x(W|<2toeL9<^)uO*_Qfac$EZZV zpCvv@Hg3(0^7{KtfmFaBHM&cb_lJT#$TeH?%egV;BpcVIQAbJ2B&KUhBb44eA%ff* zbODlBei7h1?Eq{vN-or^V~+q+K&-!vm&TBHRqt}Y9=k5``zh&ZzS};S7rmF{@aa(b znkN_QW~BStlZRJkH7U-2>~o0t#CkJ1Osfg+L919lO`yLCmqoJ)%XD&lxxK5?pISM+ z9}hrsFRN1heNorzJ>j;Yo>Ve+3y_lt+u(J?H?WN3vx%f>rndh0M?>j@B%x`EIk#Ti zc=7&DryQ&TQoQs|@B*_4*gM7Yd&nDyv@M~XlAD9nsxs8OCZlKb@d@bAQS7cp}+p&Vw34 zmJOCu7MQ#=3M&H%lL8dI2Mj-~Y1QS=oqWAqfN$#+Rn!*s4NHU=7vW;VgbK-J<#APAPNxCSxOA+zHpq?98fnJ5^{otc#PGVTw zG$Mn^T2YKh`Gk6l(vj`W>f3H>u03QTvr3CTfho^14bM)*(NnYG*t-*Qn%U(HOuw8w zf8mxQw=Ab0`_3dO8e0nSwW{BO;(Vg z6vdvmBg_NNxH%GXgwrRwlk>G!A71-GF;2No?5xd;%w1ZeA}LL`9}D9!&@|MbKpga> zX^LsyC Hwj6{;9q@F=Nq*^WDsXXh!J!ww4+bBIFw)t_q>8pF4}wmutllTem%3(I z+~Z@wv(xo5x!lHpGmI_UMI)N=kz!x%>-Hqp$3%gL~#El#gJ}^oJ(w+UCY*y z!QcusNcKBhd4LYfcT;<>qC;Lw>>#wWHZN(aDua5*NOW@BB(Q;w%a0tyJ3v9~#q$ee zLsRb+Be-MO<=DHi5d%6rHv}s0tqnP}b=h?SQ!2}cI6(-O!2pa-2L}nb?xcF?H3DZb zB#%3sY5>Z@EOZ$t5wh1%1&Brjj-cC!@up;g$+2mQFwFeQjR1_A#30q+d-{J1iuLPI!m85{Q`rnnkjYL`i9OcT5B=mt}d6Y zsT7PUS*V&V=Uylb72v)n7a1)io`#-6o==O&F-^6c8Sg^XGg>$rc?i7c;fyRCBpmFG z78i`%MHYjZYaUqwN&`?9D$&?Y1nX!5a%YT_2G<~_59VZyJmU0C!3 z9^!b1q3e>m*}YP9N7pmHP+1CA5>U$R%=(*6*x`|wwH69OiRCN|$Czg@R-~Z%rRxw6e9zSrjo#q=}LtB8ur^>kzhDv<5wk2}yG68hyTtw1k}y z%htk>aIID!oL=B|$wf5=rgG!=bTrS9a&Ao~tv5`!jUS-;xu0 zgQhvth?cQMQ&8j~AJOK6<%bN@n{c*$C`!i(52sr^Dq`^4B+?yG!DTcjj~G!2RYDx1 zbxM6a<11p=)0aelkwK>0NU2-O?=Y!%`H=XkTG}8YEI+ zP4~fCeO_+KPO?#W0BqxHV{jr_FhEkF|ZWWoqC za(TB3wJ+&HY?B6wPRh=zanvCzdusIylf2S$Pjgz>wB_#N4ig3SO*tzJkm(=Cx1(eo zh$Jj}^Vy&G=D6%OECjMYb9m5sP_ht+uD?H$^Dmr0c~RGwiWG6aWiQ#dsOw_w0GmiH zSx162rzWLJZ?vC8cKp9TKMnil|Eu5Np=U7pw!GWypqHAweagHn;}graC#sPLhE2XU zUimzFO%sVIIsn2w_mrXYbx_|8%mK2A)|gn^7JV%y z`fML7)-`egb&qf1b>5~OMYz(|HFtSxZ#;K6F|Aj2^+Yzatkg(lBtA;5TRsAEHnygc zM?|GSUP1aR(6(GTk)DkAT@70$h$oG@XHx>^dR-#s+E$u@jb?-wYqZYL!zKYOv`|2p6 zkA=sC6WPgVE%&XezMFDS?^~|}nN1R3UY|UUZV93ZClXQGd!KI*J-toLfji4yWG_j$ zfFj%vz%P-o{E^!)A=LsFV6!`XfoJm$v~I?6pZxL9ceea1-cSZIQ>i)2b4H_r>2+irshUP@V7lVfruWx(eMkRia9B9nLyf|w*%0Uol&9h zFMN=yFxwCfqZvBrmb@1TZ@U?^`bEAe@0U?7BQdYd4w`-EKxR9YFhYgyXACv!|HZ?h z&l6N!NuqtgIJ6mR>^Q(kbf6^wf$EG*W+w5uxHA$Yd8(?p1m8@rHx4cDX!t%XiN7X1 zff&wk&(<^><3C|6?i_~uB@w>*Eg`@EM;>3F;*WbiG!r)a3^x&SOhutQ9`J`T+$MtA z4vnc1)B~IZ9b1{?Hg9gA?iq4sor9etT4vClrMY(TbVC@GV!BYWecb8J{kI~j$qd|) zb5iA!yUVPXAew^aBUJILh3<4$wxdYZQ(brXY*vS4kr6qih6!|u&OkHkRgl2aIJA5+ z`9jmngr}Zby+>90a6k{iE5jdfGkIr{L}$R%Pt`MVCj&!3fJ?ihfB*@wCFD(d>G2?t z@fIAx@LYuXAd^@$NsM@ye-X|L$^)=srqhQcHu>SMWA8_N2Dd}8RPEHw0YX^$p)66v zA*oJ4fK}`=&w+&ZBCPm0mz2b!kNwD-gXxg0KBAmg?>>aOkU>cD#a>Sv^&zGgz#9}4 zr+)}?^EK&_MPZfj+nTsIfO%p18nSU@?jRf1?M6U$#Qg}j(Ri3~qqANkPVV|mDIs_A z?sU2)vdZ&DlCNsK?+cK=LAr3?mCUQCZ^>dW-WaYKd{osy5XtYv*;8GM^450=vo!lw z8SZFpFD1R!bAy)dz6Gi%djLq@o!@4o-7UWXti;qJv(r}nb@`*8?NnTA9ka@LCvo(} zl6R0UL;wO`lMGx~JAzPezu$df-gt4Jod~~$OHlp@p}O#b@DJd7MD}q&un-aO?`5i^ zsFz7+1apebH;pb|w<%#dZfWaq3T=}Z_TN;wP~oJR@7xVkY|JhNf6*JZLFExc223C8 z9uQ}w5-XZ8V|*ngm(tzh`wC3%gskvwm6|NORWEdr%nSn(36&8NuUSZ?`-_Jm0G*1s z5i;8LW@(NDvm`pgrPzD4i#gZ6j|tHRl=}`SR&9k@Wv(`oh$ldNT8jEkWEFxPbQ4`{ zh-)#=L>v(Ed+5H;5w1AQP6K!rK%?6(JhY?dfhI0qCnvAq6eRKGRP~^I$q@*Wa0m%# zJJM(%^k6JV2dk0rgNP+2afXp#1k5zz;{@X|Bv5jQaGODUTL2xX-(%{F)g8t9gTiu) z{!_^mp4($LvEV!%$M$3U1zC0_ss1wJjhEKr$Zn*NBV%^#{LmP7fkS^F5Z*OW7-?~2 zY1!KPW}@gPmpDi}X|u17Q(RBgMU0Xl@%P{tUualbxiNU-0f=8P`h#1%+~sP}`eexd zzXo;}`qF0g?#Xe^ayIKq_;ycSGhppjBKfm5H8QY!o4obKxAFI(7e_-?sNIWr%^Lk+ z@!;m&TI7nP;-9g%Vb1T*1Ry^8fK&oKnkv1`>S4)uj>%=S`4LAr6kKd zQwdwjg_frfchlhX9E=>FWMCrKEW4U)U55CHOL)@q3DRqr$g7{wPid@*W63*S7dab! zsgq~Czb8)N6RQrve9D!cs-;#A&4uf(Q01lmKmb&&8D+=}IY6bj)Ga9KhzjG;Sc5P` zeoxs@T+iVKHo{y7L2B^TqFwwpe2uJ>bJBU!;<8+I%5?S(Pfaph93B_Rm#4?daoxJe zhD_v=sjN|n*man0Ad%c(tVYjcHT%ou@dgV@Fs$D)#N0TADi zkx7vfVTI;vEh!p8`lwg2xRycgt4md!$foSk^zje-;=Vaa4Wmc8!Hog2%7Z%!>~Tso zm-{&saN7K8EC~76ap%-$Dt`Sp`tnN#oXTIA^p4*QF9hLIu-KOqMts8f17DIJwV@L4 z`8;E@`3PuOiwv1vu(9b0r}F|hXRDO7iI?DQq1NQrmqtF}UQ7@`%ZSwRY8h*wYe2k+ za!TAj_G*&^fH$Zdeya=mx&4w!M@jrP^zn>d7@JoK)}54Ki4U7+7%+ab#b zGF}!Nv)G(RXCIW%l(*Rnbfzr^#w}T3y1EyEO=v@L0+Aj zx~25U?ibGz$3m?%4^QbxJP78o$gzX#8L6s0&zu7;dSCSJny%-?1A3$P68y>Rx2DAD z=rv@H)>8B&LOC%A>nZd;Y0c?*BX81sAn0=kpAS&Z!WKxv|Algvc&u?R_dWxwTbOX} zEZqkAONJA73J0&f*ww^&ly7rP$7o2fw^<|6fG2M;o>G#?k58GQLP~i9cyoGzxSN#G zS->~d%u&l)5Eu+R=`q#ZPK=UWNvSCkb3P)&TTtz+uI&u%T<|w>Q|qwa?$xNRVr@^` zTM!`zXJ6{#2vbQA{z3oJEg|I3Nj_*!GB1)9SxEA#HJN{WiPJ5OIvNeQo0hKc9N%f) zIV4mJP*(`onP1ug-bqn~9NeKbmb+u~nhrX^_2}XgC?&gWcaZYth58OWjN5pQupTgd zeSwki)stOc)rYwWb?tjeTcVxfTrr`hXEaagp7bt$SZlm1k@1l0NdW44D)n@R8|V`D ziW`XN-R?Ls(Y&A_Wx{#q0Sx~t06X&#$QB@~Avz@t{WC^2>QXu}88TzFk%LF57l=QD zDln9k0jL*rNA-;k>EI>22_=)8U3^X~%Pr|0480%|&psvERf?VYCZmnF4)m^L68-H5 z)ojn418y1NVDHp) zL9Xz-hwD4t%yP5kSZuTWcuj8)P$@07+yJCFpDGbOuUFwsGwqmdv)L-%5gVa;kiqo} z00_vzyt`hUtQ7errk(n`Y$Z#KT9V_Wtw^?}L6U;pS@m^mv4~N|7TQcjdb=T&MrU~| z`9q@?J?}|tP_+(YYk3!+KDj}_ucZz_#698=a(i95DWEtg^h+6e90mdC9zDYEAWg=N z!#PcW^9`gL&Fnfdcq+fVBtjRBCMx%V^H2fvJz~Gc;sh7b=^B$!4-Z`B*lRt0*&ZFM zs;_SE!TLIabR3>1Xdt&H;^}Y%Ch#2dz+DEo$)GkV^iVQuino~Vdr1N&9JoBflpJ!x z?2t~`nk5c6r`9l+q6s|n!f?o4U2ub)Ar%~YXo%rMNXt2HB`xMvB|s?PBxq%9ghL)2QW|Vj4qY%qY9%$b#tLW&rnOmJRnWpX43K}L?~-&_ z89Xe(!_yC513C9@hV6pSdm#W%6Y1*g7Qfk_LxWpp-v0pOO9FhqnmP*-5ZkqMPBm2) zkbJ}Koo8F)m5J%QZGd;^WcMTHG$ez=ujQ`5_LWRRH||3KYFCdgYEarV4uCZ1J6f*n zk*|6t7qX0^f}FoYoT}f*O_)IU@(Cg7p5+lrxzwCR;xzKHm9HCj??o+3vXhg=%i;YC z!3)715w`rL>46zVPp`xK5A51MkdjUPn7lBCLKe@rBN_O8AoZ{O$2Px6GmA#19AIO3fQ_nW|%sNWwP*0Ch< z09}(b@}we%N$k=`MA(M4D|+h%ZT2)CROB}P0T!}QbdxMB$1{@T*loeN*nU8m32a|BYo%K4#`SX4IbRqrg%%B{fXRAz_Z& zAd0neLqq{_;|_ayj`}K74Z}9$&)tuZ8ZU1EGtYFya$? zE}LqZVp$7+9f7L$1o$`m1^Gj3+(EkfIRxhA!CeN?7WC{eVj^r3Zt798UAW%!-RWQ< z%eo*5(IT_T-ITi_*wfG-$lwzhVHWshQryUo9T+S?-ErWvca4CT?K_W!$Q?LrE&w$? z4yxPRh2%0ZAa}`i!Edq%o<>{?HSi~Eg>y54Q0!JOo$yE6zViACNpFwsC75ZMN}YZlrZ@k)H#`%qUUM5VOJn4FrR8R%Vd@LMCE zVz}^Yj0I2B0@^aBFuvP*m4=gvA89;2kSj&WEz_`sR%YMQF9UZI1pUQJ!=1!wV%9p{ zF&}N-%-7@82(-Q`Wl<9^J#o}^)na6@JK+Rexxo-P0`t~+(U$qX+2>rzPAbN_$#M&0NCJP8}hx0ZEvS>Iapn?vneg6l&;Zxv7B8+h^s$jTUJm z9_M{tvlF2=MsP?;xd*gw`0SB%*|BD@NAO^Q>;;rZ-5ZiVulX$B6yk*tpRpr^)Sf4> z_GT1GRMI3ekT)PC1TW0ax`K2llmeL=Dcau8?ljGOXv0D#k$o~lp@Y(WB+ir>wn41X z=h8U@<4AEYQ=tS}klikB12XTVE(m{tS2+s>7BcR^GI%{u286bnNo6Uw^`;GD8U%3y9GO^1spIk%{Wq~4Xq4iEV`xi~dMSFnyNTTTxDucWr9@y+rDxf@yA4!ZYFNb+S_MG2Qh#=&` z?#`YabZLnMkYoynI|nrTklkRcgv}XwzobecUb!R^ z-+mr(ob)y7(%ZBG>ZkSS9~e9yRXY)5RY?U~?;^evN^j|)ioD2aYk|x~16{gqZ}NOo z1&eYAvR>7a`nE9bk?mzEky@s86Ne0K*Y^%C{%~c`GjfMKcW*be&J?~C(^8$X%8U3a z&QPwo@)oDnjQ$oGng^io8wJTQ4(CF`j}F;(eHAwtMA(LV!_sk%EIvzR z<>{(|RhW$>t|iOMUh?LjxVb(TAg)>=cp16GPmjG|<-n^XOy@xQ?&^OtAOGjL>>{kV?oqQnMXYlrXyxByyCtvB0 zXOQ+VK0Hcxl5&T(G(q2Y(cR);1E0cIWk?%;TNkocpsBmXt8-i!6U|uXxQyfa@_ZYpimpm=*q)lXkbCmzlo&;z7~OY8x^q7WNA5^+ z#*jkJ$9;ii4Ng1X6u13j#R5y~*%3BnTW5o)=B0@4arlcYDOqBs{$!2)JjYjM@iljXpV#%`9|S6ZsdTEQ(P_GB@AJ)v6rbZtfYUtn0Ob2Y9t93f4#Lb zYQDN6K1nTkuNRWGc$~ZF+m`s*>ibSHcFz<*ExImKXwvA-b{yUh>zHi#c0oIcf@Qt~ z<7GsszooZlzmE!&ZYn5&4Xl{YPf672*N8lD)z()aSNhm7DVdK9yR35#Qkz(UKa@O2 zoQ=dRVd}w4T?efHwDBx3QZapC0zRy|G7PXbOZg+@$2GEt1NeUJUADf~By^(hR$p%$ zBE2UxdYQ^cQ2(R%!Ju~nskTi}{SL_@=&!fcuBR{G>~WYQ?$3B_#J4ewXCD`I%(Z%6 zpI`J?{wQTPAj13L%Y$?baq6LS0p9_H^)X{pl7H}zVM0v%59krGj5`xBqsGXq0`I0C zG8<2J>H7m-dseam^o@9M%YQla65-6=$HTVc0KNkZTfgxZ#~?__9opXQy}0Z~h=-6A z*$!FjZ$AW*;4dW)&23{2t8Z51wtA;m7g+LaK_=3ksGT7=)=iLN1Q4-P%6g4|6N>5_ zWiwt^2u_dlMw8%kX1I6w42J_;0Kf};&P%BUv`307d{MWR>?GwA*Rs2}TvbB+<4Dq2 z#MVAASmR?m=o`=iwniiZ6Pkdbu2;oCNnQdx)b&A#Jt<&EV}v=c?4i&Z>}pg~a;K|| zG+He<3ciSLV0#0M5MHB2nIuuOtpYPv0A})jHD_sn(-x6{TPMS3) zP4m81P05EWBJ&x7Ij(atl3*qm!m$d+Qs?NuWi-8YT?j@h+rlIN>&#tJG3t(fX|PNu z8&9u2LLXW}9h8vn1`(?H7lb_QH++0En6`d*Ki4Ff3EVgYJ4L%~JFctH(96j`s0S_p z9RfpRI0+DWBY_vsDB*e*~_<2#kre7FF9Jd1qYL4$aHAj#}ep?g>s;JYS%8{c>GWx5^``r-^VzrLd#_k}>9p{CM zDioC{(1yQ{b5_{Lg9%XQDW`hBh@>S2-IzdN?xmFNtEro&h7wVBh;s>y z$(alw26amzd%^^%UjTW3j%??5AmEd1OP)c z{2`S(ExV$zz8ZoWvK`i#re5=fJA35RoN;Xqz8SP99q7j)NC$F_cz({DV!pFUZO+_* zf79Y3OArr}v@}Ple1w}lgYKas-ln;3Yn}mR^A=&hB)jKP9=>fUCQ_*$YNes|5iPu} zTCPFr$*aV7$+9?LCphT<9EXtBEk46gU7d~>IHt;8K#Pm&*ks)W9U$8?tPx$)3Vq{k zw?p|uIT1#p$op;YLilbnonOAUtZJb9!gO|0OCx5()SPtDR&iKJ$K^5congiAxf$%? zVkCFm-*@)Z9o#tL;={c}LS2PnDEyw*PK6?eu@G(Scl%Z}=8?XlI{Od-8Qi!8eYO45 z&avyp4en>r_?<(HUMjmzC#mXh6_XDGU`+fgS_NV1lG_NEZ$z{F==J9L;<2MQfBT2z zkbm*yyWWEh*WzksP#L9$4mkUYIKW!H`X4?3t8$o2Xge;a;g(pE>j* z>q6q|?$^1X=&tGOPf)@WmM>6VeTQD%1~R1&|0Jn)Yak90_U!{^Fp;T3^2W=1o7~ximvpcyjoia5v;%l$2wS1^j!q`IDzJ`O&}r6PsAy z3UE|K>SfN zwf;B3wvSnGCr9H^i)nlHGbQ}BVs98M5nV)sj}&d&9Ms#CDG<7_^T=;*5wTuRJ4hse z*6xGgbmXu8Zm)fL*LGT(+srdPfM0?VNuk|2Gd}l(IX8{Qof!lp*Vz-nDBPPP$gby~ ziM1gf;&6)fw)eqVU+E6~-1{AV#x#4Fw)7h4b3IM-lw7tSt(tn#{%>hG!|3#GpqE?< zZ}^)hzqak;P&R&;npEBJQAiZKA(qC{dt9v{2U5=r!};{y-VVk?L($IaaNvj1nQae2 zy^cMB$)%1TB9WM0dKpyaI8_wgJfUC^`25q4kFRQT@!GyW+Gfjh_r%_jV<8;%PD$<;2c@Zy0@-2&q) zO4AzJA zm~PvBu>FuN^Uu0<5xI78c0lgPuN^|$e5PXujqy=ShCz^~V~DFgVrkNT8^F zL_>3ogo|#r&|sBSR&#DRFFp8Bl-@X2nXVqewvK7uRDJESvktyhSKTuSQ+jracV$&s z4M&X6F%4*Ny`^H%3Sr~Oy-|QvkL|?vJptf_<$|bhqDMk- zks2sqg!VC;nH5^6BpMJUH$J)xeIo)r`G3a}exy^RK7t>{(}TM!(0-7gQ8r-`7XC_D zCL6M8CMo0nnUuIsy^K&Nxi~ z9?luUn=t{nrGwUt+Q_!rQjHe3zs^j1)y-CS(|cKTqK%3Jzh79koDWyra!*rl|733j z;-ujqWVHf=$Bz6WYrRm?F~sr{!>JlO%>34l+#+GM8y-Yi3+j!27t9*J3hwRq`<{3W zKNC^cf-B3#NlJ<=)Ph3PhH5!iXsShW%kiP2#mj?+rkU0o^1X)y2a@C687h=EK#>Xr zPCgcM7oc91I7Y+?{*0ZiIs}Q6-vHMgxBtkj!La$9B%x6L4-$QZ=6Jk*{JbR54-^j~ zD5kgZyD`S%;Ita+*)dG1H?8Y!qkuv!9lnOjF~R!44r|(mAQ8Nr%OI^qnyZv_SI@P59G+a-*)fXwVfh_T@PTs zdQhQzcDIX1$qzt(C%Ai?hTZsjX^aDOR&c9di4?m~4Lk&C4fZ~J;p-;Zk3ifTPO+tT zSMYxQgu&s1WgTvW3%7Nqo4S!;^nR}CP7BKT*u?PlCJ*ctJF`Q;5HH2kf=ClCbitvnG{9w zDC!8A$-E^yO&Xhs6wAbhrksl{0ek&dm=w#3~u9-K^SxLE^ zR;e?hh6Mzj4#)k<09R08cMhGMM0U^a(MP8~<|(<_*D}m!|pTB0L zmqNGb>bUjNqkhS4_A#oug$jJcX=FDZ89T_OxC4cX=zZ5vkwv`eLB5zeM&lyxNZxv~ zponYtPp05_lf%V=S!Y8~&2}yt7br2mOSuj{K%={L)FsUGpwY-}y$4hb6O7Sp}@coB5+_JS^tD-SmXZ$kOYK5BzA zG@AEJi4$W$CPe485!yGsTfk7{8&_i{8@zG-UN2_&9WyI8K16xkjuJ%E*eL3w_(J{R zn{$BlOt}4kwMW6xEJ2Iq*U-A>qXh~oEG3~^MjoBd4D~YK*?kf=c5u?0eMpN>IBSRP zVea~V9zcpmj~3Y*i;P6h3%h)9-pKtv@q2vR2n@5b-~wH!c*eW6-iU!ZaWv+wMk(`y z7FB8Z8(T)XckY*cjGzxpntjJmB^(wGwp(1>2H)9Je~tt=7H)B=ANJniCz88Mdsce; zW7jpVyal2l>BSc};V=OP7mO+7RM~}DJpm3$ZS_1qoY`j{!i?AO44JVQ1@XH}ooe+JIrDgNW^Av+Ey?JLo|hi6$Nx_I06^9>~bnL@g#W6Jzh z4X$KD!j*D)@ve$ewOUUr)2)^garoLLt}6^nnKoUG6=0lXNV2f z7E-IU;911C#LAH;hp`YJeJBWpF6NXir1@}=YJ*2w7dk{2lsLWeSa#My)#qXE@bNsL zP7XcVj~~+3OTE*4JF}cOQ_dlN)i#6xCr`pDL|SudY^FK}0%a*^L&(`cjfIX8j0M!V z2ChP{AoU-u3BL=tjs6%xw6@a?8l@Q`bX)`ryVY_;at%1d)rkKV04cjhq9pI-U$~Tf zOCoeuSX*L4E)7>eH(mFQ1ecUhgQ}mhl-X&yt%c3PUh)u%IMRFSJ$_Okv08h_S-Zh{ zh1s&&B2%%~n-UKFx8~g>x!)+;iJ7zveM-SDKH9~Xz%4ofW%W3*i=4nq< zi}}+|tw}!E;vs=#4W&@I#G~$RF)m}&>4@FQzvxj?VLA92k4d(|`DW8PyMtT_t6mJD(8F-S9N6~S+$FL#nSdROUv?^9igU`XPT>d2@!T~ z(HDgN@YWH(%X^7uDfN9m#A3gf25zAYKQeJd)gn!{z~Df^W#lu0ZItQ1(5_I2UKUDR zw6-MX9)#}?=Jq_E2ZCcu(RHhSoZ8yn@*9P#+@}Z!t$AnR*Ya&app$1_4kaNLrE*)k zq=cHnWXGtDau{T%z?T5qBd&(XQ6>v|X~um=BtC=imPkG5K4hSsO9j&IIQz%B<5lek zvBu)xwt%;3X_nDu?QX99SlCdkZdFJg{N8JXze&+FHf|MW3$qM{S8W0+VQO~Ca{0?5;RmyqCHTGh%kVX*`_2F95 z0G%y1stpcKU=Pk7lo?)>#Tq%|l9u2dyhUC!%b#S>1}kj|Mr4IUl>ro0rG)0s&oyFg_Lc^({IBXd04&IOl5 z&}C*D?9tp1k1M{DQ-CjXOXMxNt|=}Dr_!*wqPvI&Z6#;dy7h`rF8j#xvgY3FoJ_DD z+?`OWY>EiYl-HYF*(#Up+x$ec>oa?YICcmx{5KUEb?qeh&e{P=fct?V<3r{|yh!~e z?$+a3(miEHDWNp{NdnEuCc6(xRBYxb&PcI!gA^CT#{j1&?@`yPhzIcH{c`PPC%RK= zGW0cjJb7yK*)*wXswYBKzmD5}-ur&ubbhpa&@#8X`=d6f^Q@iHp6rd!wy{WN-GAx! zd+X}yOrw`Tob&N0)^}t5BX71u;p$_7f21IT)wlP%Am7Pdsa6|Nu(u-@#u(qX<9|VR zN8UNB!1517bdE1>Xdc`Zude3vn;nH^u7dzHE|6j4ODI$ZM2%5pf*X~(i_6Q)9IALp zaNU;vH=B-4J0d;_ z?c6YTlOfZW?fm9P!^cuA|vxjuK%CGS}xzol$7StU~TzqAZ(Va=CxUxM9Y2C{c^;$ROQN$=XixCXW!Gy$K z;$YTNDthsJw8$_HGqw^!v|xWQ;U3bqrW9WpNxxm|IQy0>u)&?SRlxN^&a>dtg9&jd zhfk2l7W@9!Ajw}mGuo97$?RJ*<1NwnrQt4#5V|KqyVhi4SykcHr64Cy7bW-1e9j)H zJBFdx*F#yh_#t~`(nhB@<}Gn=3KF?B(BcX+bZ}w7pDXlgbMjrf*$vDP()Q*S_0gLb z;maJurrm7R@d-xKonSZu!LTj7Q=VJNV-#CS5iYUoAfv}87|b~F*38Q1K#BBTCFQ%c zIL=4!aQNzdrMM3=c4y_@X{Naxn+a)g^%WEY`Kp0yDt!TZq@2Ce&Qr-JPMvH$*+PQG zA|wyU`jOCsJb{@*Ksr-(fcd0{94FWnMJOE*gp*?AwN6XXl9Q{DB*Cf6s|&f}-7b8W zy5=GsTC{|Qo)P2TKRN^&VDE=|4+7j;JUDv0`@?pf(pt4O_Qqy7C4pV5r>&Q?I*fkx zWT(#FOSjXKqY1)PG*rY+Lo_$26@C|zk@GvkjV@jjeqIB`BBUHHhtPc_4txkIb-FP) zTJUWue~N9zYMi{QC*Eu%KNRN3JCr=#HyDvWt`rc$e9g?HxdGj<7tuA=1p-6VjT)ayqgpL!8*?a9f_cm#{3(PHQk z1&L(y-;oH7lJ4IFlCp6r*oM(ZoF!07y^cf$erQx8DA8|={qCZ1lE_h?@T5K z`)s5f=dHnab|yFM9-2gu4epSxCA(LN1-5O@OMK-MvvOD0jC{W5k`OF!Od=+)sG?Eu%=2p1Io1bgkKF_5 zbsd}vODB&12qt^3-zrB;R%I>~J-vmC=Hfz#M{Zn|si^q$+=6ZUyLZa_eu4ATJ?^^j zRl?JozG+>{z0Y6}lk)7wEc`DM61^j=ZJZ6uZ1{1f?YB;6oPBg<19D}0x+na|o7i%j z(sBrBi|)2j6^GG(d%uf*vd;qF^gFuiF@qaFI4WZ)NAHY~`?%$OnoyhumOKyKTlP9V zO?_6X8@37Q?KXM_@@c<|n-u#>8dcE3Jc5=$P+TF+SbQJZkEA**ox<4!uVe zoFoVQ1%;?TcLRKzZUI02N<|Y(y#Y;Aip9bv{vo$hv8S5u|Nes=y=4lCPg{8mVWW;R zrjacJcxybaxF;zXIJqbA;g1rA-R?>RtiqTDRIRrE#wc9N zP`%rNv5Ar1%1JY{%C_ZlOV?w2Ck^z{1y6+`jI|Rr9rL@g z)Vd{zSJ`zj>)G-vIF|TS^U$w)-0REVG$Q%pn+ZIpv09*v+--RgbO>^HF>sA-mgl_uQ7 zJq(o5P5?6d5n2o;A}aroHNQL7z(5ga4UAdHSzLn-!85XLk$A*|yur6?I8so`2AClZ zX$)d{H$92 zGl|D>;F}cBW$O-zywkx`VwW7h2NGDPYU!QoZBmj%e63@_H$|Kai2x#pNSBJ}X<4~A zEq~icBFY}AKSpjHIaHW?{q8Wf@cX9U9T=RBL&8)bg07=x(L_FB4mt^GxQOo_ZAw5d z^ax29Q&mO~E(9JD;Cj~6o;g`R6?Ykkf6%At6XB)pwz0?Dd)mEH{IGs{g*I-Bl{FAZeC~)q-9gsX&Gg$&3Q#0LVEM$06}dB0zTt10gvwYKFSeVDJV(JD$aj zYvB<_#6c|hju#3_S#pFyPm{+s7q{RyW$)%S1 zVmlJl7*gSWJ#4=gh&qF}<30ntaZZR)~Mv zIPCm{DkT6`K&ihzos2oLTSo+5f)adba+DUnCz#&)Q^D}cVIsPSd}kv5GJw5|XRq&7 zxitNrtxEN^m0ac}0g?lZZ_BPL>ndG8SLvD4j=JjjNXfvdz6tZIVgPQJ`<(~(H4`Jb zXm`!oAtmI-ZBRFJ>NJtT0c9Sd_!z^ZI&;2p7?z?BjsTK1m912@|pSl|d1;Y@oL8s=jjI)v{NyQ@x z$hz2wU}h?5HOXq+7@8xEEzC*S=I#eNUs`VeDo?sA?*4;* z#)IowrY(H~vv5I@=`2b#aDN`mJbNas`x9Wx0`HK7q$W&~o4W7P z`&|&Ci~kZz`~1F5*Q37Mvc5aF+j_V3cy?%Cawxo$D0IK;9plpbCFzwwTYmFS>cuRd zR2Ih$ol2D=;>Dv%Pm-P`>jguz*fis!g_cDIfYZ23JhP)Go6VQ5l{4F?Q)lOUmgI8# zF6BY^3escO&MRff-61yQ?p-swq+!K&>=5>z)uwrVJ+{3vXuw-yl-;Bm$AS52;{mk^ zEbV}8vb>9YHL8}$uqI50A1o-F$y z)T&hOV#=m99W+NP9n)QlAl!wX`*P&+hjT%A3XnRwsM%iI@JIfj(7-YG;P-knG97tu zo#+s$;3;t(#bVozJ-wMk6GlLRJrI(&WMdB(4ge@%r_5rNR zrM-8T$`;r=HS{ESPkZmnWL)&VGARibd2ae|dvh9U_O5)Ct|%h$;&A6vihZg@5k}NT zWSrC@Zg$F06bL5pj6Mny_IAd$WM@`7k%)x66_7R51 zV}`TtBn|tEQzyuPhs0FHl|czf#M9IKIBdCCq>E<|_!Q4U*E=6sh>)yzigNI^f>PIL zOu`$_19cd{?Dab|({BTzH=ZZqH;yMS*cS$%x)HE(0mDIo^gGgekFCydv%TWkX}m2z zObKEDi4ekL%bbJy_T4_>lweCbcZ(!v={J)C4J~VQGF6X^40z2&zyuf}*i;gRB1c7{ z^at00lXqD?KF5^1Uze-&$D1OqH82C95En^Kos25#vg{CmRo-f_3AyPyZ2@4OTGn8@ zk{=b_2o7C=$9x;2Riv%nZ~`{~dJDRbes?;3sNcufN5Uql2IP4x0ZW~EI3!8zA*Tj( zk4@#s;=?JkG8)k@nVOyqdVz;upYD2xPs+`QHF*Fa?>L!z$N*{(1A2WF?omJy)`K9TBnqtgzye|a#x03qb#7{fNV!jpeN?r z>vwpp9w!0YyPo+1-m3wNJ(hr_BETCJ?MVvm)Q=xJ2%?Lr+Cd82?dW=qk1X`vpq5~T zpGl>UN3JCf3U7&ssmoq&iTMRw8zM#M4Zj3XoQLA@orlfh5h64$2;QJDb72~qI zaJPie{P$x^0u^pGETMZy8RV3UYQkb|y4Jsqod738-Hz_uZM{a>KBNc%WA_u*^1M3=Jw!XzwP(CPWk$`)4z z>c_WstemQ?y_0yq*9`rl29MdIrB6#r zGcV~auBEnYu9PLOI4MF>(bJ@;E`&+*>=oNcW7wT;-SuUSTB3*IoBAF<@#^|2UQ;K& z5qYng%~FDB5927}xY(fk1%A&@EPHmw=Tg{JpD+Y@cxkl7!H1 zQm-@*HCGRlo_qvzsa%ndYJFUjuQY1&F`EE#6V%u7O-!;T20B6wo5@6d2Oh?UQ>3!r zW;W*8%c_pEnEA=+d^+aUxGKIjFM3);nr*(We^$=l-`fMy&v?nEt>E!W3_6`wO%~sh zw>fy(a=Ow{nuks^j@C-EM0sx~!#vjW&dQV=#|G1mY!yj)1^z`#BN+ib%P+)Uy5Dch zJxgj-C-5uvRws~5@7-VprV?H~cWx|=bGLka>9`vEw7jqkUtn`<{o6gWUn>C7Z~C3Q zM=LUpA}f8xAtWJ}-pB6fACb*M($b#JZ4Nm0Yi2NVF^IMs$=ZN9f{$RQ*Yxcg^}fYL za}Jy^bpdbq@F&+j)Y1=RlV{1S zlERK7kgC|tpwB~Z(~mL?U;os5t~VHO3GVP8!lmyWc)B*WZW{wXKMJ4%SCEI31Oe?@ zA>W2On0xQzjkU*~!+CGAe#we1N5>D_{rkK1)|lu|B~6Aj$jr4?9WgH2(5mkP6W2>$ z=VYO8^H1gH<_waVCcr*}*4`EQCch^au=m5s*YvL;7ko7WjeA_F53sMiiRqQmbot%F ziD~ED7aWlupy6?YG|*wJ4MUy%Q{A8i2`zZ&^vPfK(r^LyDiZ{s8=%h$+;qp@;nQok zAcx~^Dr~8H(36y!`ymj$_ou5{_09%6zO&(B)st~@D))p##-CQdNQ)f2Bmj(qpdFGt zQ|EIe7YCpnF8j?7B77b!m|sw;GF9IJtoc6BS@_L9o10y-w3l+!r2_xO&y1!9`>4-c zMq3W6G07IlPm@r)qybr;L7@%qPN4bgqW6wa?nel`wxfrVbfmcqXEPjmj1fd;Y++9- zG15tp-hu+%v`GCukfELlqef%=3p8c{FAa8)i3b!+ILR|EKOx*Lt(=R& zos$gS@HR;@3SnP#l%+mE4j7o_tTRt{#mwFukWY8aMK~g_cv|gg;5r_*Rl0z@GOT)7 zVL}UTj$ph&075PlX(`P~x;x(Qr|afLgJ*|}P9Q8uYa|)~M_dtiV6MqO#q0F?9WGu} zz_6@OvdX=Sb$x)>jVfTGy&41=)ZjW16y7{Bu%P7tykSV);oqkgeKUVV3NpN5*NrkF z;;JfS(>Z94xE-Dz{hrzRnjlbX zmqSQblC8```ke}z-WjpgAjDiFRY%EdLf!~4&P^=J(}E?BqlTEVe} z0|oL%{Ov3+Y?0&2?6#x9MRJSH2CgxJ4TRH8Vv2Hi%(+7iCdz*vUH$IV6WYu>N~8@5 z`6PK?-Va=1rsAbR%g7xQUgX^|?7h#vsTN#TFWYP7Vg=GL?wbaxvc1a3pk9Yh_cjYs z^Il2UI~JOXe5%&nDd~p%=Hr{~d@)3!22TnTLFdKgJj5Fmpjym`f_gyR-ljBf&mB03 z&~}K8_IVTo#Dz_YaQ@Yutkp|6j2p7c*G+~FmC^N$XWDwbZ4qFPh* z%`Vv+bUsJiUy4iQ1ZtYA;<1P!h4MlF4w3Sb& zjXtVM#>XZ9SRdP)tVPpVZRSol5vM?px!8#W4#QFqmxR)@up~YMLP5sEo~t#rNTSKE zu`xu!DFT5X#DnJRCEmbyJ#U0dqfL(j@y2G43gDsWcbI7L-3VJUcnGgQ=R@f1Q^Jq%HsX7fz)3Xt zh1aFYVuNVtz7xYAAnRtXvCpRw^qu*`=FRa=8?$}C);GCn)W@(>-;{t8g{C^H<{Dxz zBX&fS4gU$nzt*eIt?eUapuKM_`ysHhfn_FDxG7e@ekglN7iA^Ocr_0A$e@6UK(=`_ z0tvq%7z>2wI#B#9C0DV3?m-_U37H(u5)!4Cv;-}*_?`+T7b*wq!yoqCS3CR(>U4I&hhqa za&>K9$*VNUbT75TEqxH&5jDoieq_i>DF>@-ZcUTBZ}4}GwZPG|iRt)e`5xf=2k!oi z=mhb-9|2n&S!H#2cI$Xx(%GE;+UkJ$NgS^CLLGA^PM&x4H79-Q1x7Yd_Sif+#)a4EpBiey6INtAG;#~>lu~W%&@9+8Cowndi z(XU$g8y8acJf**`HT1Jf!RTryNIg#B-Z8HUm(L<-}5L3Nd zh0`SyYfkqL=+4aKBZ^R&sw?S~0fv~zOg1gBPH0808XU7A`b^S^K$G9WWibP5JGX*h zB-r3Q!s%duh`wxMGy@!PK;lQ_n!F%jR_KS9S{ElE; zcp0%c=ts(o4uuDsMg(4?{a~FFDrvZ&>4Jkh_ravn@KfCPwEa_Y|CHQ_r;+4<8az`g z`le1sP_B&bEs81PBMidn5sp+{BlC`^Zd5mm>eb*8uu6I)0VvAvy^FtFgNB$_=ibU~ z5E_zNasn#$)QwwMrpQjY)_2mw7go$r0SZxrV&TT8<-a%JT~%ugzS=O3y*9{ z<2O+b`V=*ST;${)JddH?NQg)BQ^*3azA5DimW+N!`W%M?tFbV|1VLCa?p_5_=I~na z_k*$=ohuXTnZN217}#BTJp2d9R12q;slA>aUg<4W`>w2?{*-Hbt7qr%W_J+NdSuB* zfdIozDP$3FE(%uUi!*r1_Lfv}f$<`jrpZO*&P+U}%H3+8Ch^eD@k}@TXc%&07&W1#>@MIn&EeVkQTunK5E!{T#>H*baX_6i&F2@FjetX34IR_&a_NCsI@&R@u zA@`&dL0PC@;CeybaRezBC9_I+$H>A2^ z`fwHw&Z4upXT-iS4u|gyjH8VVi!2U{)TWVlQkl^cxmq?7?;t1n!{4RY{>z5&@d2JF}+tJ zq4K+l%W-g`y5O+m2kD4s*ISJ{v$&`!Y_xl!;dr%yc(?cRq;IHCDq!yPQWqzjyMsd9 zw{kf|M^qL1ULRL{Q2I^wAvX zeU*Xvhtx~dE&#tH;?`h8%F&M>=L<_uzhkbpX4O2|Z-+P}S*x zo{nj6IgsQ?U3;^LW-Zn3 zQz%K~Ewht>z7zlUkY?UcPj4jjNrX6zKDkrT?`GB!2_Em_@wVt;R??Pc?`OK2$Gwac zJ50Jl(5^MKi#LvM-^c;rca~%v_v^jH2p%}ELw?hA20DJ?)n0SfrqiZA?fGr#oUOxY z8_vn~GRdd6t}nVSi>%6mY-{&}v+mg)dc^(UnN8HO{Iz>DXLXV5gU;TxJv_0#U_VbU zv(0KPYW59ziulinp&>NmO9-bC=e6Z$=Q7hM!P<+ZiB)zk zo(mXo>_^eY()*3Ul;ey83)v~9_&lQ%>uEP|Fq%+20DTi>1BU^9ez$O$QJeyNo?W_< zL!!Gy?eMgb$Kt@iJLd0XlA+t!fGBdyOcSM zGkp81-tmZ#1n2B^;^3E#B9h*9M)XQ)P8SU;&ZXEE*0>&+*pV%{Qn;Hw7p+1`tTRid zNw$%{^7@TfaQEJco1_!4HnC{1QiwliWQ@8|2Qu3N(6B(w(eKQ@k<_;Y*-6bXoEXi_ za>*fGPQ_lpNBd|vyMs$^t9PM-UrxKR-UyJFr?JZdw{{jsHhLX7EQ%vBe6n&z0>-L$ zKx=N<4QmcFP75#7&CIaB1XBj|JLp>TXhz*@f|3grBG7sRHkcpy5p5D*K_qHJhzx?| z7KlQ4jeZ|VRg4VCQ13j%2^l$}(ViL=IZS;E`eunWr+KH47bQ)0$(h~_rdP4eXd31Z zirI_A(e1u1pNave+;^;dqoP{bN?>60<@_9NUKSsWcG7ux5S%vEWR@7vTF@mlZ~9CT7#SF}1IHW4>Lq{&zoS&(#vVm$pmuYTIR+35 z4VIz?PlP.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�_-SH9on61TX_^J#&uaI?(S3VL-bN`D~-$6@J}J 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 z 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%0D6cTmb;4-UZII}_nLB&MNdFy^ZDD)d@1 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 z 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%0A6b?=Qh7Wy`XbsiULc zE#M{6$cPi>P5C*8DuO#=9GKuv#HO-~(jA`*?J{C+*9#qfxPM)`;J1LvR&_KaAQI

  • +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -1406,6 +1049,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index a88d6899f..e4ba6c1c6 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -14,13 +14,12 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/hosted-version.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] @@ -212,174 +211,6 @@ By following these steps, you've learned how to: With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. - -## Build with Connect - -[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] - -## See It In Action - -Wormhole Connect is deployed live in several production apps. Here are a few: - -- [Portal Bridge](https://portalbridge.com/){target=\_blank} -- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} -- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} - -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). - -## Next Steps - -
    - -- :octicons-tools-16:{ .lg .middle} **Get Started Now** - - --- - - Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. - - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) - -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** - - --- - - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - - - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - - -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** - - --- - - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) - -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** - - --- - - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. - - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -## Introduction {: #introduction } - -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. - -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. - -## Features {: #features } - -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: - -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination - -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. - -## Integrate Connect {: #integrate-connect } - -### Import Directly into a React App {: #import-directly-into-a-react-app} - -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - -```bash -npm i @wormhole-foundation/wormhole-connect -``` - -Now you can import the React component: - -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; - -function App() { - return ; -} -``` - -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} - -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. - -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; - -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); - -wormholeConnectHosted(container); -``` - -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. - -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. - - ```html - -
    - - - - ``` - - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: - - ```html - -
    - - - - ``` - -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. - -## Configuration {: #configuration} - -This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. - -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: - - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available - -For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- @@ -1054,6 +885,14 @@ categories: Connect, Transfer Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + ## Prerequisites Before you begin, make sure you have the following: @@ -1065,7 +904,7 @@ Before you begin, make sure you have the following: - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) -## Install and Setup Project +## Install and Set Up Project 1. Clone the demo repository and navigate to the project directory: @@ -1140,13 +979,89 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. +Use the following guides to configure your Connect instance: -For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/guides/hosted-version/ +--- BEGIN CONTENT --- +--- +title: Integrate Connect via CDN +description: +categories: Connect, Transfer +--- + +# Integrate Connect via CDN + +[Wormhole Connect](/docs/products/connect/overview/){target=\_blank} is a prebuilt UI component that makes it easy to transfer tokens across chains. You can integrate it into any website using either React or a hosted version served via [jsDelivr](https://www.jsdelivr.com/){target=\_blank}. + +This guide focuses on using the hosted version—ideal for simpler setups or non-React environments. It includes everything you need to get started with just a few lines of code. + +If you're using React, refer to the [Get Started with Connect](/docs/products/connect/get-started/){target=\_blank} guide. + +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + +## Add Connect to Your Project Using the Hosted Version + +The hosted version uses pre-built packages (including React) served via jsDelivr from npm. To integrate it without using React directly, add the following to your JavaScript project: + +```js +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; + +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'bridge-container' not found"); +} + +wormholeConnectHosted(container); +``` + +You can provide config and theme parameters in a second function argument: + +```js +import { + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; + +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'connect' not found"); +} + +wormholeConnectHosted(container, { + config: { + rpcs: { + // ... + } + }, + theme: { + background: { + default: '#004547', + } + } +}); +``` + +## Next Steps + +Use the following guides to configure your Connect instance: + +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- @@ -1780,7 +1695,7 @@ Here are some key use cases that highlight the power and versatility of Connect: Add Connect to your app with these key setup steps: -[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/connect/overview/connect-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ @@ -1884,366 +1799,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -3221,7 +2776,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -3250,6 +2805,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -3265,6 +2824,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 3dd7766f8..527941d23 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -14,8 +14,6 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/tutorials/treasury-proposal.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/multigov/get-started.md [type: other] @@ -244,136 +242,6 @@ governor.execute(targets, values, calldatas, descriptionHash); Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/multigov/ ---- BEGIN CONTENT --- ---- -title: Getting Started with MultiGov -description: Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -categories: MultiGov ---- - -# MultiGov - -## Begin the MultiGov Integration Process - -Take the following steps to get started with a MultiGov integration: - -1. Evaluate if [MultiGov](/docs/learn/governance/) meets your cross-chain governance needs -2. Fill out the intake form on the [Tally website](https://www.tally.xyz/get-started){target=\_blank} -3. The Tally team will review your application and contact you to discuss implementation details -4. Work with the Tally team to customize and deploy MultiGov for your specific use case - -## Start Building - -
    - -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** - - --- - - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. - - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) - -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** - - --- - - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. - - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** - - --- - - Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. - - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) - -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** - - --- - - Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. - - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) - -- :octicons-question-16:{ .lg .middle } **Technical FAQs** - - --- - - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. - - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) - -
    - -## Additional Resources - -
    - -- :octicons-book-16:{ .lg .middle } **What is MultiGov?** - - --- - - Need to familiarize yourself with MultiGov? Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. - - [:custom-arrow: Learn the basics](/docs/learn/governance/) - -- :octicons-checklist-16:{ .lg .middle } **Tutorials** - - --- - - Access step-by-step tutorials for executing cross-chain governance actions, including treasury management proposals with MultiGov. - - [:custom-arrow: Learn by building](/docs/tutorials/multigov/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/governance/overview/ ---- BEGIN CONTENT --- ---- -title: MultiGov Overview -description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -categories: MultiGov ---- - -# MultiGov: Cross-Chain Governance with Wormhole - -## Overview - -### What Is MultiGov and Why Is It Important? - -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. - -MultiGov is important because it: - -- **Increases participation** by allowing token holders from multiple chains to engage in governance -- **Enhances security** by leveraging Wormhole's robust cross-chain communication -- **Improves scalability** by integrating any chain supported by Wormhole -- **Enables unified governance** and coordinated decision-making across multiple networks - -### Key Features - -- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains -- **Cross-chain voting** - token holders on any integrated chain can cast votes -- **Vote aggregation** - votes from all chains are collected and tallied on the hub -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Wormhole integration** - secure and reliable cross-chain communication -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain - -### High-Level Architecture Diagram - -The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. - -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. - - -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ --- BEGIN CONTENT --- --- @@ -1178,366 +1046,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -2515,7 +2023,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2544,6 +2052,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -2559,6 +2071,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 202a19b23..6d6fc7e5b 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -13,12 +13,6 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/concepts/security.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/configuration/access-control.md [type: other] @@ -28,602 +22,14 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/post-deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/troubleshoot.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- - -# Native Token Transfers - -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. - -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. - -## Quickstart - -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: - -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] - -## Deploy NTTs with Launchpad - -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. - -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. - -## Additional Resources - -
    - -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** - - --- - - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. - - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) - -- :octicons-question-16:{ .lg .middle } **NTT FAQs** - - --- - - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- - -# Install the Native Token Transfers CLI - -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. - -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. - -
    - -## Install NTT CLI - -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: - -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} - -Follow these steps to install the NTT CLI: - -1. Run the installation command in your terminal: - - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` - -2. Verify the NTT CLI is installed: - - ```bash - ntt --version - ``` - -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI - -## Update NTT CLI - -To update an existing NTT CLI installation, run the following command in your terminal: - -```bash -ntt update -``` - -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. - -For local development, you can update your CLI version from a specific branch or install from a local path. - -To install from a specific branch, run: - -```bash -ntt update --branch foo -``` - -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` - -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. - -## Where to Go Next - -
    - - -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** - - --- - - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** - - --- - - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -categories: NTT, Transfer ---- - -# Native Token Transfers Post Deployment - -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment - -## Manual Relaying for Solana Transfers - -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. - -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. - -## Where to Go Next - -
    - -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** - - --- - - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. - - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) - -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** - - --- - - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. - - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ ---- BEGIN CONTENT --- ---- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -categories: NTT, Transfer ---- - -# Managers and Transceivers - -## Managers - -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: - -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain - - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` - -- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer - - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` - -- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected - - ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner - ``` - -## Transceivers - -_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: - -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system - - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager - ``` - -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees - - ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) - ``` - -## Lifecycle of a Message - -### EVM - -#### Transfer - -A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. - -**Events** - -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); -``` - -#### Rate Limit - -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. - -If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. - -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. - -If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. - -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. - -**Events** - -```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); -``` - -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` - -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` - -#### Send - -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). - -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. - -**Events** - -```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); -``` - -#### Receive - -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. - -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. - -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. - -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. - -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. - -**Events** - -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); -``` - -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` - -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); -``` - -#### Mint or Unlock - -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. - -**Events** - -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` - -### Solana - -#### Transfer - -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. - -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. - -Depending on the mode and instruction, the following will be produced in the program logs: - -```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` - -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. - -#### Rate Limit - -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. - -If the transfer amount fits within the current capacity: - -- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. - -If the transfer amount doesn't fit within the current capacity: - -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error - -#### Send - -The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. - -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. - -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: ReleaseOutbound -``` - -#### Receive - -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. - -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: ReceiveMessage -``` - -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: Redeem -``` - -#### Mint or Unlock - -The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. - -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. - -Depending on the mode and instruction, the following will be produced in the program logs: - -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- - -# Deployment Models - -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. - -## Hub-and-Spoke - -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain - -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - -## Burn-and-Mint - -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - -This model best suits new token deployments or projects willing to upgrade existing contracts. - -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- - -# Native Token Transfers - -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - -## Introduction - -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. - -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. - -## Key Features - -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: - -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - -## Integration Paths - -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. - -### Native Token Transfers Framework - -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. - -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: - -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} - -### Token Bridge - -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains - -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. - -## Supported Token Standards - -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ --- BEGIN CONTENT --- --- @@ -1059,6 +465,31 @@ Yes. NTT tokens can be used with chains that do not support NTT by leveraging th - **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. + +## How can I update my NTT CLI version? + +To update an existing NTT CLI installation, run the following command in your terminal: + +```bash +ntt update +``` + +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. + +For local development, you can update your CLI version from a specific branch or install from a local path. + +To install from a specific branch, run: + +```bash +ntt update --branch foo +``` + +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` + +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ @@ -1919,166 +1350,55 @@ Enter a new value to adjust limits and click **Update**. The changes will take e ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. -categories: NTT, Transfer ---- - -## Native Token Transfers Overview - -Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. - -## Key Features - -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps - - -## Deployment Models - -NTT offers two operational modes for your existing tokens: - -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token - -## Supported Token Standards - -Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. - -The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. - -NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. - -## Deployment Process - -Here's a breakdown of the key steps involved when deploying NTT: - -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed - -## Use Cases - -- **Cross-Chain Swaps and Liquidity Aggregation** - - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution - -- **Borrowing and Lending Across Chains** - - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time - -- **Gas Abstraction** - - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains - -- **Cross-Chain Payment Widgets** - - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens - -- **Cross-Chain Staking** - - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains - -## Next Steps - -Follow these steps to get started with NTT: - -[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ ---- BEGIN CONTENT --- ---- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer ---- - -# NTT CLI Commands - -## Introduction - -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. - -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. - -## Table of Commands - -The following table lists the available NTT CLI commands, descriptions, and examples. - -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/post-deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer +--- -### General Commands +# Native Token Transfers Post Deployment -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
    ` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): -### Configuration Commands +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| +## Manual Relaying for Solana Transfers -### Solana Commands +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. ## Where to Go Next
    - -- :octicons-gear-16:{ .lg .middle } **Configure NTT** +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** --- - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. - [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** --- - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk)
    --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/troubleshoot/ --- BEGIN CONTENT --- --- title: Troubleshooting NTT Deployment @@ -2086,7 +1406,7 @@ description: Resolve common issues in NTT deployment with this troubleshooting g categories: NTT, Transfer --- -# Troubleshooting NTT Deployment +# Troubleshoot Your NTT Deployment If you encounter issues during the NTT deployment process, check the following common points: @@ -2187,379 +1507,476 @@ If you encounter issues during the NTT deployment process, check the following c ``` --- END CONTENT --- -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ --- BEGIN CONTENT --- --- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer --- -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} +## Native Token Transfers Overview -
    -
    +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. +## Key Features -
    -
    +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps -## Borrowing and Lending Across Chains -Let users borrow assets on one chain using collateral from another. +## Deployment Models -
    -
    +NTT offers two operational modes for your existing tokens: -🛠 **Wormhole products used:** +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time +## Supported Token Standards -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. -
    -
    +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. -
    -
    +## Deployment Process -## Real-Time Price Feeds and Trading Strategies +Here's a breakdown of the key steps involved when deploying NTT: -Fetch price feeds across multiple chains for DeFi applications. +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed -
    -
    +## Use Cases -🛠 **Wormhole products used:** +- **Cross-Chain Swaps and Liquidity Aggregation** -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +- **Borrowing and Lending Across Chains** -
    -
    + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time +- **Gas Abstraction** -
    -
    + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains -## Asset Movement Between Bitcoin and Other Chains +- **Cross-Chain Payment Widgets** -Enable direct BTC transfers without wrapped assets. + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens -
    -
    +- **Cross-Chain Staking** -🛠 **Wormhole products used:** + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains +## Next Steps -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} +Follow these steps to get started with NTT: -
    -
    +[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] +--- END CONTENT --- -
    -
    +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +--- BEGIN CONTENT --- +--- +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer +--- -## Decentralized Social Platforms +# NTT CLI Commands -Enable seamless communication and asset transfer across decentralized social networks. +## Introduction -
    -
    +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -🛠 **Wormhole products used:** +If you haven't installed the NTT CLI yet, follow the [NTT Installation](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank} instructions to set it up before proceeding. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards +## Table of Commands -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} +The following table lists the available NTT CLI commands, descriptions, and examples. -
    -
    +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +### General Commands -
    -
    +| Command | Description | Example | +|-----------------------------------------|--------------------------------------------------------|--------------------------------------------------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest` | +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0` | +| `ntt clone
    ` | initialize a deployment file from an existing contract | `ntt clone Mainnet Solana Sol5678...` | +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | -## Memecoin Launchpads +### Configuration Commands -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. +| Command | Description | Example | +|----------------------------------------------|-----------------------------------------|------------------------------------------------| +| `ntt config set-chain ` | set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key` | +| `ntt config unset-chain ` | unset a configuration value for a chain | `ntt config unset-chain Ethereum scan_api_key` | +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key` | -
    -
    +### Solana Commands -🛠 **Wormhole products used:** +| Command | Description | Example | +|------------------------------------------------|----------------------------------------------------------|-------------------------------------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json` | +| `ntt solana token-authority ` | print the token authority address for a given program ID | `ntt solana token-authority Sol1234...` | +| `ntt solana ata ` | print the token authority address for a given program ID | `ntt solana ata Mint123... Owner123... token22` | -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes +## Where to Go Next -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems +
    -
    -
    +- :octicons-gear-16:{ .lg .middle } **Configure NTT** -
    -
    + --- -## Cross-Chain Perpetuals + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) -
    -
    +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -🛠 **Wormhole products used:** + --- -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/)
    -
    +--- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/managers-transceivers/ +--- BEGIN CONTENT --- +--- +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +categories: NTT, Transfer +--- -
    -
    +# Managers and Transceivers -## Gas Abstraction +## Managers -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: -
    -
    +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain -🛠 **Wormhole products used:** + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) + ``` -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` -
    -
    +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner + ``` -
    -
    +## Transceivers -## Bridging Intent Library +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -
    -
    + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -🛠 **Wormhole products used:** +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +## Lifecycle of a Message -
    -
    +### EVM +#### Transfer -
    -
    +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. -## Multichain Prediction Markets +**Events** -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); +``` -
    -
    +#### Rate Limit -🛠 **Wormhole products used:** +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. -
    -
    +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. -
    -
    +**Events** -## Cross-Chain Payment Widgets +```ts +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); +``` -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` -
    -
    +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` -🛠 **Wormhole products used:** +#### Send -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). -🔗 **Used in:** E-commerce, Web3 payments, and subscription models +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. -
    -
    +**Events** +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` -
    -
    +#### Receive -## Oracle Networks +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. -
    -
    +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. -🛠 **Wormhole products used:** +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +**Events** -
    -
    +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` -
    -
    +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -## Cross-Chain Staking +#### Mint or Unlock -Enable users to stake assets on one chain while earning rewards or securing networks on another. +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -
    -
    +**Events** -🛠 **Wormhole products used:** +```ts +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); +``` -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks +### Solana -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +#### Transfer -
    -
    ---- END CONTENT --- +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -# Glossary +Depending on the mode and instruction, the following will be produced in the program logs: -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` -## Chain ID +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +#### Rate Limit -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. -## Consistency Level +If the transfer amount fits within the current capacity: -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. -## Delivery Provider +If the transfer amount doesn't fit within the current capacity: -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -## Emitter +#### Send -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. -## Finality +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. -## Guardian +The following will be produced in the program logs: -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +```ts +Program log: Instruction: ReleaseOutbound +``` -## Guardian Network +#### Receive -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. -## Guardian Set +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +The following will be produced in the program logs: -## Heartbeat +```ts +Program log: Instruction: ReceiveMessage +``` -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +The following will be produced in the program logs: -## Observation +```ts +Program log: Instruction: Redeem +``` -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +#### Mint or Unlock -## Relayer +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. -A relayer is any process that delivers VAAs to a destination. +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. -## Sequence +Depending on the mode and instruction, the following will be produced in the program logs: -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock +``` +--- END CONTENT --- -## Spy +## Basics Concepts [shared: true] -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -## VAA +--- -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +## List of shared concept pages: -## Validator -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- @@ -3538,7 +2955,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -3567,6 +2984,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -3582,6 +3003,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index a8d7a1762..8422e78a5 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -13,8 +13,6 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md [type: other] @@ -23,531 +21,6 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/queries/overview/ ---- BEGIN CONTENT --- ---- -title: Queries Overview -description: Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -categories: Queries ---- - -# Queries Overview {: #queries-overview } - -Wormhole Guardians, who run full nodes for various connected chains, facilitate a new cross-chain query service that allows for on-demand attested responses to queries, bypassing the inefficiencies of traditional transaction-based data retrieval. This method is faster and cost-effective, eliminating the need for gas payments and transaction finality wait times. - -!!! note - Queries are currently in closed beta, though you can start developing today. Check out [Use Queries](/docs/build/queries/use-queries/){target=\_blank} and reach out to [Join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data. The current implementation provides integrators with a simple REST endpoint to initiate an off-chain request via a proxy. The proxy then forwards the request to the Guardians and gathers a quorum of responses. The result returns the encoded response, including the request details and the Guardian signatures. The request validation performed by the query module includes a three step process that involves verifying the signature to ensure it has the correct prefix, confirming that the signer is authorized to execute query requests, and validating the legitimacy of all per-chain requests contained in the query. You can read more about Queries in the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank}. - -## The Flow of a Query {: #the-flow-of-a-query} - -The general overview of a query's flow is as follows: an off-chain process sends HTTPS query requests to a Query Proxy, which validates and forwards them to the Guardians; these Guardians independently validate, sign, and return the response, with the entire process typically taking less than a second. - -![The architecture flow of a query](/docs/images/build/queries/overview/overview-1.webp) - -The step-by-step flow of a query is as follows: - -1. An off-chain process initiates a query request via HTTPS to the query proxy (or Query Server) -2. The query proxy validates the request and forwards it to the Guardians via a gossip network -3. The Guardians independently validate the request, make the requisite RPC calls, verify the results, sign, and gossip a response back to the Query Proxy -4. The Query Proxy aggregates the results and returns a response when it reaches a quorum of two-thirds or more of the current Guardian set - the exact quorum requirements as the core bridge -5. The off-chain process can then submit these requests to an on-chain contract which should verify the signatures and validate the request before processing the result - -In this flow, the Query Proxy is a permissioned but trustless part of the protocol. In most cases, this entire process takes less than one second. If a request is invalid or cannot be processed by the Guardians, they will retry for up to one minute before timing out. Requests can be batched to have the Guardians make multiple calls to multiple networks. This can further reduce overhead for processing query responses on-chain. Up to 255 queries can be batched together, with certain types allowing for batching themselves. - -## Supported Query Types {: #supported-query-types} - -There are currently five supported types of queries. See [the white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank} for more details on each. - -### eth_call {: #eth-call} - -This query type is effectively an equivalent of [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a block specified by number or hash. - -Calls are batched to allow specifying multiple calls (even to multiple contracts) against the same block. These calls are included in a single batch RPC call, simplifying on-chain verification. Up to 255 calls may be batched in an single `eth_call` query. - -The result contains the specified block number, hash, timestamp, and the call result. - -### eth_call By Timestamp {: #eth-call-by-timestamp} - -This query type is similar to `eth_call` but targets a timestamp instead of a specific `block_id`. This can be useful when forming requests based on uncorrelated data, such as requiring data from another chain based on the block timestamp of a given chain. - -The result also contains the target and block details with the following enforced conditions: `target_block.timestamp <= target_time < following_block.timestamp` and `following_block_num - 1 == target_block_num`. - -### eth_call With Finality {: #eth-call-with-finality} - -This query type is similar to `eth_call` but ensures that the specified block has reached the specified finality before returning the query results. The finality may be `finalized` or `safe.` Note that if a chain doesn't natively support the `safe` tag, this will be equivalent to `finalized.` - -### sol_account {: #sol_account} - -This query is used to read data for one or more accounts on Solana, akin to [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank}. - -### sol_pda {: #sol_pda} - -This query is used to read data for one or more [Program Derived Addresses(PDA)](https://www.anchor-lang.com/docs/pdas){target=\_blank} on Solana, akin to calling [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} on the result of `PublicKey.findProgramAddressSync(seeds, programId).` This query is helpful for times when you want to more generally read accounts owned by a program and verify the derivation on another chain, like how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. - -## Supported Chains {: #supported-chains} - -The following table provides expected support based on testing. However, the success of any given query is based on the success of the underlying call on each Guardian’s RPC node. - -For example, many chains have implementations forked from [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which keeps 128 blocks of state in memory by default (without running in archive mode). While this is good for about 25 minutes of history on Ethereum Mainnet, it is only about three minutes on Optimism. While Guardian nodes can be expected to have access to recent state, there are currently no guarantees of how far back in history they have access to. - -### Mainnet {: #mainnet} - -| Chain | Wormhole Chain ID | eth_call | By Timestamp | With Finality | Expected History | -|:-------------:|:-----------------:|:--------:|:------------------:|:-------------:|:----------------:| -| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | -| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | -| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | -| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | -| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | -| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | -| Karura | 11 | ✅ | ✅ | ✅ | archive | -| Acala | 12 | ✅ | ✅ | ✅ | archive | -| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | -| Celo | 14 | ✅ | ℹ️ hints required\* | ✅ | 128 blocks | -| Moonbeam | 16 | ✅ | ℹ️ hints required\* | ✅ | 256 blocks | -| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | -| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | -| Base | 30 | ✅ | ✅ | ✅ | archive | - -\*`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. - -## Next Steps {: #next-steps} - -Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. - -Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. - -You can also check out the following examples of applications that make use of Wormhole Queries: - -- [Basic demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/queries/use-queries/ ---- BEGIN CONTENT --- ---- -title: Use Queries -description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -categories: Queries ---- - -# Use Queries - -You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. - -This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. - -## RPC Basics - -Before digging into anything Queries-specific, this page will look at how to make an [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a public Ethereum RPC. Suppose you'd like to query the WETH contract for its total supply; before making a request, you need some information about the contract you want to call, including: - -- **To** - the contract to call. WETH is [0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2){target=\_blank} -- **Data** - the method identifier and ABI-encoded parameters, which can be obtained as follows: `web3.eth.abi.encodeFunctionSignature("totalSupply()")` which yields `0x18160ddd` -- **Block ID** - the block number, hash, or tag. Tag options include `latest,` `safe,` or `finalized` - -The prepared curl request is as follows: - -```bash title="eth_call JSON-RPC request" -curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' -``` - -And the corresponding response is: - -```bash title="eth_call JSON-RPC reponse" -{ - "jsonrpc":"2.0", - "id":1, - "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" -} -``` - -Converting the returned value of the executed call from hexidecimal results in the value `3172615244782286193073777`. You can compare your result to the [**Read Contract**](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#readContract){target=\_blank} tab in Etherscan. Your result will be different as WETH is minted/burned over time. - -## Construct a Query {: #construct-a-query} - -You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. - -```jsx -npm i @wormhole-foundation/wormhole-query-sdk axios -``` - -In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. - -You can request the latest block from a public node using `eth_getBlockByNumber`. - -```jsx - -await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; -``` - -Then construct the call data. - -```jsx -to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; -``` - -Finally, put it all together in a `QueryRequest`. - -```jsx -const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); -``` - -This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. - -```jsx - -// { -// "nonce": 0, -// "requests": [ -// { -// "chainId": 2, -// "query": { -// "callData": [ -// { -// "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", -// "data": "0x18160ddd" -// } -// ], -// "blockTag": "0x11e9068" -// } -// } -// ], -// "version": 1 -// } -``` - -## Mock a Query - -For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. - -```jsx -const mockData = await mock.mock(request); - console.log(mockData); -// { -// signatures: ['...'], -// bytes: '...' -// } -``` - -This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. - -```jsx -const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -// Mock Query Result: 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee (3172556167631284394053614) -``` - -Testing this all together might look like the following: - -```jsx -import { - EthCallData, - EthCallQueryRequest, - EthCallQueryResponse, - PerChainQueryRequest, - QueryProxyMock, - QueryRequest, - QueryResponse, -} from '@wormhole-foundation/wormhole-query-sdk'; -import axios from 'axios'; - -const rpc = 'https://ethereum.publicnode.com'; -const callData: EthCallData = { - to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; - -(async () => { - const latestBlock: string = ( - await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; - if (!latestBlock) { - console.error(`❌ Invalid block returned`); - return; - } - console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); - const targetResponse = await axios.post(rpc, { - method: 'eth_call', - params: [callData, latestBlock], - id: 1, - jsonrpc: '2.0', - }); - // console.log(finalizedResponse.data); - if (targetResponse.data.error) { - console.error(`❌ ${targetResponse.data.error.message}`); - } - const targetResult = targetResponse.data?.result; - console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); - // Form the query request - const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); - console.log(JSON.stringify(request, undefined, 2)); - const mock = new QueryProxyMock({ 2: rpc }); - const mockData = await mock.mock(request); - console.log(mockData); - const mockQueryResponse = QueryResponse.from(mockData.bytes); - const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -})(); -``` - -### Fork Testing - -It is common to test against a local fork of Mainnet with something like - -```jsx -anvil --fork-url https://ethereum.publicnode.com -``` - -In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. - -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. - -```jsx -npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe -``` - -If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. - -## Make a Query Request - -The standardized means of making a `QueryRequest` with an API key is as follows: - -```jsx -const serialized = request.serialize(); -const proxyResponse = (await axios.post)( - QUERY_URL, - { - bytes: Buffer.from(serialized).toString('hex'), - }, - { headers: { 'X-API-Key': YOUR_API_KEY } } -); - -``` - -Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. - -A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` - -A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` - -## Verify a Query Response On-Chain - -A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: - -```bash -forge install wormhole-foundation/wormhole-solidity-sdk -``` - -Broadly, using a query response on-chain comes down to three main steps: - - 1. Parse and verify the query response - 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract - 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: - - Is the request against the expected chain? - - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing - - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks - - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases - - Is the result of the expected length for the expected result type? - 4. Run `abi.decode` on the result - -See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. - -??? code "View the complete `QueryDemo`" - ```solidity - // contracts/query/QueryDemo.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; -import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "wormhole-solidity-sdk/QueryResponse.sol"; - -error InvalidOwner(); -// @dev for the onlyOwner modifier -error InvalidCaller(); -error InvalidCalldata(); -error InvalidForeignChainID(); -error ObsoleteUpdate(); -error StaleUpdate(); -error UnexpectedResultLength(); -error UnexpectedResultMismatch(); - -/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. -contract QueryDemo is QueryResponse { - using BytesParsing for bytes; - - struct ChainEntry { - uint16 chainID; - address contractAddress; - uint256 counter; - uint256 blockNum; - uint256 blockTime; - } - - address private immutable owner; - uint16 private immutable myChainID; - mapping(uint16 => ChainEntry) private counters; - uint16[] private foreignChainIDs; - - bytes4 public GetMyCounter = bytes4(hex"916d5743"); - - constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { - if (_owner == address(0)) { - revert InvalidOwner(); - } - owner = _owner; - - myChainID = _myChainID; - counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); - } - - // updateRegistration should be used to add the other chains and to set / update contract addresses. - function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { - if (counters[_chainID].chainID == 0) { - foreignChainIDs.push(_chainID); - counters[_chainID].chainID = _chainID; - } - - counters[_chainID].contractAddress = _contractAddress; - } - - // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. - function getMyCounter() public view returns (uint256) { - return counters[myChainID].counter; - } - - // getState() returns this chain's view of all the counters. It is meant to be used in the front end. - function getState() public view returns (ChainEntry[] memory) { - ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); - ret[0] = counters[myChainID]; - uint256 length = foreignChainIDs.length; - - for (uint256 i = 0; i < length;) { - ret[i + 1] = counters[foreignChainIDs[i]]; - unchecked { - ++i; - } - } - - return ret; - } - - // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. - function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { - ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); - uint256 numResponses = r.responses.length; - if (numResponses != foreignChainIDs.length) { - revert UnexpectedResultLength(); - } - - for (uint256 i = 0; i < numResponses;) { - // Create a storage pointer for frequently read and updated data stored on the blockchain - ChainEntry storage chainEntry = counters[r.responses[i].chainId]; - if (chainEntry.chainID != foreignChainIDs[i]) { - revert InvalidForeignChainID(); - } - - EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); - - // Validate that update is not obsolete - validateBlockNum(eqr.blockNum, chainEntry.blockNum); - - // Validate that update is not stale - validateBlockTime(eqr.blockTime, block.timestamp - 300); - - if (eqr.result.length != 1) { - revert UnexpectedResultMismatch(); - } - - // Validate addresses and function signatures - address[] memory validAddresses = new address[](1); - bytes4[] memory validFunctionSignatures = new bytes4[](1); - validAddresses[0] = chainEntry.contractAddress; - validFunctionSignatures[0] = GetMyCounter; - - validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); - - require(eqr.result[0].result.length == 32, "result is not a uint256"); - - chainEntry.blockNum = eqr.blockNum; - chainEntry.blockTime = eqr.blockTime / 1_000_000; - chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); - - unchecked { - ++i; - } - } - - counters[myChainID].blockNum = block.number; - counters[myChainID].blockTime = block.timestamp; - counters[myChainID].counter += 1; - } - - modifier onlyOwner() { - if (owner != msg.sender) { - revert InvalidOwner(); - } - _; - } -} - ``` - -## Submit a Query Response On-Chain - -The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. - -This example submits the transaction to the demo contract: - -```jsx -const tx = await contract.updateCounters( - `0x${response.data.bytes}`, - signaturesToEvmStruct(response.data.signatures) -); -``` ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- @@ -943,366 +416,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -2280,7 +1393,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2309,6 +1422,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -2324,6 +1441,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 121f782cd..9cc3b7850 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -565,366 +565,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -1902,7 +1542,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -1931,6 +1571,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -1946,6 +1590,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index de536c699..86da80493 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -13,7 +13,6 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] @@ -22,54 +21,6 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- - -# Wormhole Settlement Overview - -## Introduction - -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ --- BEGIN CONTENT --- --- @@ -676,366 +627,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -2013,7 +1604,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2042,6 +1633,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -2057,6 +1652,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index a46bd4eaa..bc6c04e27 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -13,15 +13,15 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/cli/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/dev-env.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ +Doc-Content: https://wormhole.com/docs/tools/cli/get-started/ --- BEGIN CONTENT --- --- title: Wormhole CLI @@ -80,7 +80,7 @@ Options: ### Subcommands -??? code "Aptos" +??? interface "Aptos" ```bash worm aptos INSERT_COMMAND @@ -110,7 +110,7 @@ Options: --version Show version number [boolean] ``` -??? code "Edit VAA" +??? interface "Edit VAA" ```bash worm edit-vaa INSERT_COMMAND @@ -139,7 +139,7 @@ Options: --guardian-secret, --gs Guardian's secret key [string] ``` -??? code "EVM" +??? interface "EVM" ```bash worm evm INSERT_COMMAND @@ -162,7 +162,7 @@ Options: --rpc RPC endpoint [string] ``` -??? code "Generate" +??? interface "Generate" ```bash worm generate INSERT_COMMAND @@ -180,7 +180,7 @@ Options: -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] ``` -??? code "Info" +??? interface "Info" ```bash worm info INSERT_COMMAND @@ -208,7 +208,7 @@ Options: --version Show version number [boolean]
    ``` -??? code "NEAR" +??? interface "NEAR" ```bash worm near INSERT_COMMAND @@ -230,7 +230,7 @@ Options: -r, --rpc Override default rpc endpoint url [string] ``` -??? code "Parse" +??? interface "Parse" ```bash worm parse INSERT_VAA @@ -242,7 +242,7 @@ Options: --version Show version number [boolean] ``` -??? code "Recover" +??? interface "Recover" ```bash worm recover INSERT_DIGEST INSERT_SIGNATURE @@ -255,7 +255,7 @@ Options: --version Show version number [boolean] ``` -??? code "Status" +??? interface "Status" ```bash worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH @@ -328,7 +328,7 @@ Options: --version Show version number [boolean] ``` -??? code "Submit" +??? interface "Submit" ```bash worm submit INSERT_VAA @@ -407,7 +407,7 @@ Options: [boolean] [default: false] ``` -??? code "Sui" +??? interface "Sui" ```bash worm sui INSERT_COMMAND @@ -436,7 +436,7 @@ Options: --version Show version number [boolean] ``` -??? code "Transfer" +??? interface "Transfer" ```bash worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK @@ -561,7 +561,7 @@ Options: --rpc RPC endpoint [string] ``` -??? code "Verify VAA" +??? interface "Verify VAA" ```bash worm verify-vaa INSERT_VAA, INSERT_NETWORK @@ -572,10 +572,9 @@ Options: -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] ``` - ## Examples -### VAA generation +### Generate a VAA Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: @@ -599,7 +598,7 @@ worm generate attestation --emitter-chain ethereum \ --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 ``` -### VAA parsing +### Parse a VAA Use `parse` to parse a VAA into JSON: @@ -647,7 +646,7 @@ payload: { } ``` -### Submitting VAAs +### Submit VAAs Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): @@ -676,7 +675,7 @@ worm submit $(cat guardian-upgrade.txt) --network mainnet --chain celo The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. -### Getting Info +### Fetch Contract Information To get info about a contract (only EVM supported at this time), use the following command: @@ -759,8 +758,6 @@ Running this command generates the following output: } ``` -### Additional Info Examples - You can get the contract address for a module as follows: ```bash @@ -773,6 +770,8 @@ To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can worm info contract mainnet bsc NFTBridge ``` +### Fetch Chain Information + You can get the RPC address for a chain as follows: ```bash @@ -786,7 +785,7 @@ worm info rpc mainnet bsc ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ +Doc-Content: https://wormhole.com/docs/tools/dev-env/ --- BEGIN CONTENT --- --- title: Local Dev Environment @@ -851,7 +850,7 @@ https://api.wormholescan.io ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ +Doc-Content: https://wormhole.com/docs/tools/faqs/ --- BEGIN CONTENT --- --- title: Toolkit FAQs @@ -1311,42 +1310,32 @@ categories: Solidity-SDK # Solidity SDK -## Introduction - -The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains. +This page covers all you need to know about the functionality offered through the Wormhole Solidity SDK. -By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides: +
    - - **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure - - **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain - - **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement - - **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments +- :octicons-download-16:{ .lg .middle } **Installation** -These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains. + --- -This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing. + Find installation instructions using Foundry and Forge to pull the necessary libraries into your project. -## Installation + [:custom-arrow: Install the SDK](/docs/tools/solidity-sdk/get-started/#installation) -To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project: +- :octicons-download-16:{ .lg .middle } **Source Code** -```bash -forge install wormhole-foundation/wormhole-solidity-sdk@v0.1.0 -``` + --- -When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file: + Want to go straight to the source? Check out the Solidity SDK GitHub repository. -```toml -evm_version = "paris" -``` + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} -This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades. +
    ## Key Considerations Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind: - - **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes - **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries - **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments @@ -1376,7 +1365,18 @@ Please refer to the complete `WormholeRelayerSDK.sol` file below for further det ???- code "`WormholeRelayerSDK.sol`" ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/constants/Chains.sol"; +import "wormhole-sdk/Utils.sol"; + +import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; +import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; +import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; +import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; ``` ### Base Contract Overview @@ -1386,20 +1386,87 @@ The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/bl - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:22:28 + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } ``` - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:45:54 + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } ``` These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. ???- code "`Base.sol`" ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/interfaces/IWormhole.sol"; +import "wormhole-sdk/Utils.sol"; + +abstract contract Base { + IWormholeRelayer public immutable wormholeRelayer; + IWormhole public immutable wormhole; + + address registrationOwner; + mapping(uint16 => bytes32) registeredSenders; + + constructor(address _wormholeRelayer, address _wormhole) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + wormhole = IWormhole(_wormhole); + registrationOwner = msg.sender; + } + + modifier onlyWormholeRelayer() { + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } + + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } + + /** + * Sets the registered address for 'sourceChain' to 'sourceAddress' + * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid + * + * Assumes only one sender per chain is valid + * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) + */ + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } +} ``` ### Interface for Cross-Chain Messages @@ -1434,7 +1501,32 @@ This section covers cross-chain messaging and token transfers and shows how to u To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; + +contract CrossChainSender is Base { + constructor( + address _wormholeRelayer, + address _wormhole + ) Base(_wormholeRelayer, _wormhole) {} + + function sendMessage( + bytes memory message, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Register sender and send message through WormholeRelayer + setRegisteredSender(targetChain, msg.sender); + onlyWormholeRelayer().sendPayloadToEvm( + targetChain, + address(targetAddress), + message, + 0, + 500_000 + ); + } +} ``` This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. @@ -1444,7 +1536,26 @@ This contract extends `Base.sol` and allows sending cross-chain messages securel The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenSender is TokenSender { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenSender(_wormholeRelayer, _wormhole) {} + + function sendToken( + address token, + uint256 amount, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Send tokens across chains + transferTokenToTarget(token, amount, targetChain, targetAddress); + } +} ``` In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. @@ -1454,7 +1565,28 @@ In this example, `TokenSender` initiates a token transfer to another chain. The To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenReceiver is TokenReceiver { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenReceiver(_wormholeRelayer, _wormhole) {} + + // Function to handle received tokens from another chain + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable override { + // Process the received tokens here + receiveTokens(payload); + } +} ``` In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. @@ -1486,366 +1618,6 @@ This context is provided to help understand how the system works under the hood, ## Full content for shared concepts: -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- - -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID - -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. - -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. - -## Consistency Level - -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - -## Delivery Provider - -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - -## Emitter - -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - -## Finality - -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - -## Guardian - -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. - -## Guardian Network - -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - -## Guardian Set - -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - -## Heartbeat - -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -## Observation - -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence - -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - -## Spy - -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - -## VAA - -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - -## Validator - -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- @@ -2823,7 +2595,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2852,6 +2624,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -2867,6 +2643,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index df41344f1..ca62305b8 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -13,308 +13,15 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/token-bridge-contracts.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md [type: other] ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Get Started with Token Bridge -description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -## Introduction - -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. - -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Token Bridge, you'll need the following: - -- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers - -## How to Interact with Token Bridge Contracts - -The primary functions of the Token Bridge contracts revolve around: - -- **Attesting a token** - registering a new token for cross-chain transfers -- **Transferring tokens** - locking and minting tokens across chains -- **Transferring tokens with a payload** - including additional data with transfers - -### Attest a token - -Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. - -The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. - -```solidity -function attestToken( - address tokenAddress, - uint32 nonce -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `tokenAddress` ++"address"++ - - The contract address of the token to be attested. - - --- - - `nonce` ++"uint32"++ - - An arbitrary value provided by the caller to ensure uniqueness. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the attestation transaction. - -When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. - -You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. - -### Transfer Tokens - -Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. - -Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. - -```solidity -function transferTokens( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint256 arbiterFee, - uint32 nonce -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `token` ++"address"++ - - The address of the token being transferred. - - --- - - `amount` ++"uint256"++ - The amount of tokens to be transferred. - - --- - - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. - - --- - - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. - - --- - - `arbiterFee` ++"uint256"++ - Optional fee to be paid to an arbiter for relaying the transfer. - - --- - - `nonce` ++"uint32"++ - A unique identifier for the transaction. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. - -Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. - -```solidity -function completeTransfer(bytes memory encodedVm) external; -``` - -??? interface "Parameters" - - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. - -!!!note - - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain - -### Transfer tokens with payload - -While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. - -Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. - -```solidity -function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `token` ++"address"++ - - The address of the token being transferred. - - --- - - `amount` ++"uint256"++ - The amount of tokens to be transferred. - - --- - - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. - - --- - - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. - - --- - - `nonce` ++"uint32"++ - A unique identifier for the transaction. - - --- - - `payload` ++"bytes memory"++ - Arbitrary data payload attached to the transaction. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. - -After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. - -Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. - -```solidity -function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); -``` - -??? interface "Parameters" - - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. - -??? interface "Returns" - - `bytes memory` - - The extracted payload data. - -## Source Code References - -For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: - -- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} -- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} - -## Portal Bridge - -A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - -### How Does It Work? - -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. - -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). - -### Token Transfer Flow - -The transfer process is simple yet secure, involving a few key steps: - -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody - -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) - -### Key Features of the Token Bridge - -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - -### Message and Payload Structure - -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract - -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - -### Security and Authorization - -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - -### Portal Bridge - -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ --- BEGIN CONTENT --- --- @@ -1130,462 +837,324 @@ Now that you've completed a manual multichain token transfer, explore these guid - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/token-bridge-contracts/ --- BEGIN CONTENT --- --- -title: Token Bridge Overview -description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +title: Get Started with Token Bridge +description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. categories: Token-Bridge, Transfer --- -# Token Bridge Overview +# Interact with Token Bridge Contracts -The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. +## Introduction -This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -## Key Features +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. -Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: +## Prerequisites -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +To interact with the Wormhole Token Bridge, you'll need the following: -## How It Works +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers -The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: +## How to Interact with Token Bridge Contracts -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +The primary functions of the Token Bridge contracts revolve around: -This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. +- **Attesting a token** - registering a new token for cross-chain transfers +- **Transferring tokens** - locking and minting tokens across chains +- **Transferring tokens with a payload** - including additional data with transfers -```mermaid -sequenceDiagram - participant Alice - participant Ethereum - participant GuardianNetwork - participant Solana +### Attest a token - Alice->>Ethereum: Lock ETH in Token Bridge contract - Ethereum->>GuardianNetwork: Emit transfer message - GuardianNetwork->>GuardianNetwork: Verify and sign message +Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. - GuardianNetwork->>Solana: Submit signed message - Solana->>Solana: Verify message and mint wrapped ETH (WETH) +The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. - Solana->>Alice: Deliver wrapped ETH on Solana +```solidity +function attestToken( + address tokenAddress, + uint32 nonce +) external payable returns (uint64 sequence); ``` -For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. - -## Use Cases - -Here are key use cases that highlight the power and versatility of the Token Bridge. - -- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards - -- **Tokenized Gaming Rewards** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains - -- **Multichain DeFi Arbitrage** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms - -## Next Steps - -If you are looking for more guided practice, take a look at: - -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge ---- END CONTENT --- - -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - +??? interface "Parameters" -
    -
    + `tokenAddress` ++"address"++ + + The contract address of the token to be attested. -## Cross-Chain Perpetuals + --- -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. + `nonce` ++"uint32"++ -
    -
    + An arbitrary value provided by the caller to ensure uniqueness. -🛠 **Wormhole products used:** +??? interface "Returns" -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences + `sequence` ++"uint64"++ + + A unique identifier for the attestation transaction. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. -
    -
    +You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. +### Transfer Tokens -
    -
    +Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. -## Gas Abstraction +Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +```solidity +function transferTokens( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint256 arbiterFee, + uint32 nonce +) external payable returns (uint64 sequence); +``` -
    -
    +??? interface "Parameters" -🛠 **Wormhole products used:** + `token` ++"address"++ + + The address of the token being transferred. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments + --- -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements + `amount` ++"uint256"++ + The amount of tokens to be transferred. -
    -
    + --- + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -
    -
    + --- -## Bridging Intent Library + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. + --- -
    -
    + `arbiterFee` ++"uint256"++ + Optional fee to be paid to an arbiter for relaying the transfer. -🛠 **Wormhole products used:** + --- -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents + `nonce` ++"uint32"++ + A unique identifier for the transaction. -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +??? interface "Returns" -
    -
    + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. +Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. -
    -
    +```solidity +function completeTransfer(bytes memory encodedVm) external; +``` -## Multichain Prediction Markets +??? interface "Parameters" -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + `encodedVm` ++"bytes memory"++ + + The signed VAA containing the transfer details. -
    -
    +!!!note + - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation + - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -🛠 **Wormhole products used:** +### Transfer tokens with payload -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. -
    -
    +```solidity +function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload +) external payable returns (uint64 sequence); +``` +??? interface "Parameters" -
    -
    + `token` ++"address"++ + + The address of the token being transferred. -## Cross-Chain Payment Widgets + --- -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. + `amount` ++"uint256"++ + The amount of tokens to be transferred. -
    -
    + --- -🛠 **Wormhole products used:** + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers + --- -🔗 **Used in:** E-commerce, Web3 payments, and subscription models + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -
    -
    + --- + `nonce` ++"uint32"++ + A unique identifier for the transaction. -
    -
    + --- -## Oracle Networks + `payload` ++"bytes memory"++ + Arbitrary data payload attached to the transaction. -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +??? interface "Returns" + + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. -
    -
    +After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. -🛠 **Wormhole products used:** +Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +```solidity +function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); +``` -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +??? interface "Parameters" -
    -
    + `encodedVm` ++"bytes memory"++ + The signed VAA containing the transfer details. -
    -
    +??? interface "Returns" -## Cross-Chain Staking + `bytes memory` -Enable users to stake assets on one chain while earning rewards or securing networks on another. + The extracted payload data. -
    -
    +## Source Code References -🛠 **Wormhole products used:** +For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks +- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} +- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +## Portal Bridge -
    -
    +A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..learn/glossary/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer --- -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID +# Token Bridge Overview -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. -## Consistency Level +## Key Features -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -## Delivery Provider +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +## How It Works -## Emitter +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain -## Finality +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana -## Guardian + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) -## Guardian Network + Solana->>Alice: Deliver wrapped ETH on Solana +``` -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. -## Guardian Set +## Use Cases -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +Here are key use cases that highlight the power and versatility of the Token Bridge. -## Heartbeat +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +- **Tokenized Gaming Rewards** -## Observation + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +- **Multichain DeFi Arbitrage** -## Relayer + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms -A relayer is any process that delivers VAAs to a destination. +## Next Steps -## Sequence +If you are looking for more guided practice, take a look at: -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +--- END CONTENT --- -## Spy +## Basics Concepts [shared: true] -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -## VAA +--- -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +## List of shared concept pages: -## Validator -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- @@ -2564,7 +2133,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -2593,6 +2162,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -2608,6 +2181,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index d252e3d38..1d06d751f 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -14,27 +14,15 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/tutorials/react-dapp.md [type: tutorials] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/cctp-contracts.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/data.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/hosted-version.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md [type: other] @@ -47,9 +35,11 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/post-deployment.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/troubleshoot.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] @@ -58,6 +48,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/token-bridge-contracts.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md [type: other] ## Full content for each doc page @@ -247,7 +238,225 @@ By following these steps, you've learned how to: With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/cctp/ +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with CCTP +description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. +categories: Transfer +--- + +# Get Started with CCTP + +## Introduction + +[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. + +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. + +You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. + +## Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} + +This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. + +## Configure Your Token Transfer Environment + +1. Create a new directory and initialize a Node.js project: + + ```bash + mkdir cctp-bridge + cd cctp-bridge + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` + +3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: + + ```bash + touch transfer.ts helper.ts + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. + + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a CCTP Transfer + +This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. + +Start by defining utility functions for signer and token setup: + +1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: + + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } + + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: + + ```ts title="transfer.ts" + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helper'; + +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) + const wh = await wormhole('Testnet', [evm, solana, sui]); + + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); + + // Get signer from local key + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); + + // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; + + const automatic = false; + + // Create the circleTransfer transaction (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); + + const quote = await CircleTransfer.quoteTransfer( + sendChain, + rcvChain, + xfer.transfer + ); + console.log('Quote: ', quote); + + // Step 1: Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); + + // Step 2: Wait for Circle Attestation (VAA) + const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); + + // Step 3: Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); + + process.exit(0); +})(); + ``` + +3. Run the script to execute the transfer: + + ```bash + npx tsx transfer.ts + ``` + + You will see terminal output similar to the following: + +
    +npx tsx transfer.ts +Starting Transfer +Started Transfer: + [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', + '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] + +Waiting for Attestation +Retrying Circle:GetAttestation, attempt 0/60 +Retrying Circle:GetAttestation, attempt 1/60 + +Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] + +Completing Transfer +Completed Transfer: + [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] + +
    + +To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. + +## Next Steps + +Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: + + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/cctp-contracts/ --- BEGIN CONTENT --- --- title: Interacting with CCTP Contracts @@ -255,11 +464,11 @@ description: Learn how to interact directly with Circle's CCTP Bridge contracts, categories: Transfer --- -# Get Started with CCTP +# Interact with CCTP Contracts ## Introduction -Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. +Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/products/cctp-bridge/overview/){target=\_blank} is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. @@ -2871,1786 +3080,344 @@ function receivePayloadAndUSDC( To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ --- BEGIN CONTENT --- --- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer +title: CCTP Bridge with Wormhole +description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. +categories: Transfer --- -# Wormhole Connect - -Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. - -## Build with Connect - -[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] +# CCTP with Wormhole Overview -## See It In Action +The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. -Wormhole Connect is deployed live in several production apps. Here are a few: +## Key Features -- [Portal Bridge](https://portalbridge.com/){target=\_blank} -- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} -- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} +- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. +- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. +- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. +- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. +- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. +- **Gas payment**: Covering destination gas in automated vs. manual transfers. + - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. + - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). +## How It Works -## Next Steps +This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. -
    +1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. -- :octicons-tools-16:{ .lg .middle} **Get Started Now** +2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. - --- +3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. - Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. +4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) +5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** +```mermaid +sequenceDiagram + participant User as Alice + participant SourceChain as Circle Bridge
    on Ethereum + participant Circle + participant Guardians as Wormhole Guardians + participant Relayer + participant DestinationChain as Circle Bridge
    on Avalanche - --- - - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. - - - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) - - -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** + User->>SourceChain: Submit transfer
    (100 USDC to Avalanche) + SourceChain->>Circle: Initiate a burn + Circle->>Circle: Burn USDC and provide attestation + SourceChain->>Guardians: Emit Wormhole message (transfer metadata) + Guardians->>Guardians: Sign message and produce VAA + Relayer->>Guardians: Fetch signed VAA + Relayer->>Circle: Fetch Circle burn attestation + Relayer->>DestinationChain: Submit VAA and
    attestation + DestinationChain->>Circle: Verify Circle attestation + Circle->>User: Mint USDC to Alice +``` - --- +!!! note + For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +## Use Cases - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) +Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** +- **USDC Payments Across Chains** + - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. + - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. - --- +- **USDC-Powered Multichain Settlement** + - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. +## Next Steps - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) +Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: -
    +- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. +- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ --- BEGIN CONTENT --- --- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. +title: Routes +description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. categories: Connect, Transfer --- -# Wormhole Connect +## Routes Overview {: #routes-overview} + +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. -## Introduction {: #introduction } +Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. +## Token Bridge Routes {: #token-bridge-routes} -## Features {: #features } +The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: +#### Manual Route {: #manual-route} -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination +The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. +#### Automatic Route {: #automatic-route} -## Integrate Connect {: #integrate-connect } +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. -### Import Directly into a React App {: #import-directly-into-a-react-app} +## CCTP Routes (USDC) {: #cctp-routes-usdc} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} +Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. -```bash -npm i @wormhole-foundation/wormhole-connect -``` +#### Manual Route {: #manual-route-cctp} -Now you can import the React component: +This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; +#### Automatic Route {: #automatic-route-cctp} -function App() { - return ; -} -``` +Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} +## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; +#### Manual Route {: #manual-route-ntt} -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. -wormholeConnectHosted(container); -``` +#### Automatic Route {: #automatic-route-ntt} + +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. +## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). - ```html - -
    - - - - ``` +#### Automatic Route {: #automatic-route-eth} - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: +Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. - ```html - -
    - - - - ``` +## USDT Bridge Route {: #usdt-bridge-route} + +Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. + +#### Automatic Route {: #automatic-route-usdt} -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. +Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. -## Configuration {: #configuration} +## tBTC Route {: #tbtc-route} -This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. +You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: +Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available +#### Manual Route {: #manual-route-tbtc} -For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer +title: Connect Data Configuration +description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +categories: Connect, Transfer --- -# Native Token Transfers +## Data Configuration -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. +This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. +## Get Started -## Quickstart +Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +=== "React integration" -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + } +} -## Deploy NTTs with Launchpad + + ``` -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. +=== "Hosted integration" -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. + ```ts + import WormholeConnect, { + wormholeConnectHosted, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -## Additional Resources +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; -
    +const container = document.getElementById('bridge-container'); -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** +wormholeConnectHosted(container, { + config, +}); + ``` - --- +!!! note + The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. +## Examples {: #examples } - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) +### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. - --- +=== "Mainnet" - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; -
    ---- END CONTENT --- +function App() { + return ; +} + ``` -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- +=== "Testnet" -# Install the Native Token Transfers CLI + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. +const config: WormholeConnectConfig = { + // You can use Connect with testnet chains by specifying "network": + network: 'Testnet', + chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], + rpcs: { + Avalanche: 'https://rpc.ankr.com/avalanche_fuji', + BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', + }, +}; -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +function App() { + return ; +} + ``` -
    +!!! note + For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. -## Install NTT CLI +### Configuring Routes -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: +By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} +#### Available Route Plugins -Follow these steps to install the NTT CLI: +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -1. Run the installation command in your terminal: +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route +- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route +- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` +In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. -2. Verify the NTT CLI is installed: +For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. - ```bash - ntt --version - ``` +#### Example: Offer Only CCTP Transfers -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: -## Update NTT CLI +```typescript +import WormholeConnect, { + AutomaticCCTPRoute, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -To update an existing NTT CLI installation, run the following command in your terminal: +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], +}; -```bash -ntt update +; ``` -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. +#### Example: Offer All Default Routes and Third-Party Plugins -For local development, you can update your CLI version from a specific branch or install from a local path. +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -To install from a specific branch, run: +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -```bash -ntt update --branch foo -``` +import { myNttConfig } from './consts'; // Custom NTT configuration -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` - -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. - -## Where to Go Next - -
    - - -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** - - --- - - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) - -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** - - --- - - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -categories: NTT, Transfer ---- - -# Native Token Transfers Post Deployment - -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment - -## Manual Relaying for Solana Transfers - -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. - -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. - -## Where to Go Next - -
    - -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** - - --- - - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. - - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) - -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** - - --- - - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. - - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ ---- BEGIN CONTENT --- ---- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -categories: NTT, Transfer ---- - -# Managers and Transceivers - -## Managers - -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: - -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain - - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` - -- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer - - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` - -- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected - - ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner - ``` - -## Transceivers - -_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: - -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system - - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager - ``` - -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees - - ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) - ``` - -## Lifecycle of a Message - -### EVM - -#### Transfer - -A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. - -**Events** - -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); -``` - -#### Rate Limit - -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. - -If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. - -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. - -If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. - -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. - -**Events** - -```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); -``` - -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` - -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` - -#### Send - -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). - -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. - -**Events** - -```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); -``` - -#### Receive - -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. - -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. - -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. - -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. - -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. - -**Events** - -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); -``` - -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` - -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); -``` - -#### Mint or Unlock - -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. - -**Events** - -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` - -### Solana - -#### Transfer - -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. - -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. - -Depending on the mode and instruction, the following will be produced in the program logs: - -```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` - -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. - -#### Rate Limit - -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. - -If the transfer amount fits within the current capacity: - -- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. - -If the transfer amount doesn't fit within the current capacity: - -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error - -#### Send - -The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. - -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. - -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: ReleaseOutbound -``` - -#### Receive - -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. - -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: ReceiveMessage -``` - -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - -The following will be produced in the program logs: - -```ts -Program log: Instruction: Redeem -``` - -#### Mint or Unlock - -The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. - -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. - -Depending on the mode and instruction, the following will be produced in the program logs: - -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Get Started with Token Bridge -description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -## Introduction - -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. - -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. - -## Prerequisites - -To interact with the Wormhole Token Bridge, you'll need the following: - -- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers - -## How to Interact with Token Bridge Contracts - -The primary functions of the Token Bridge contracts revolve around: - -- **Attesting a token** - registering a new token for cross-chain transfers -- **Transferring tokens** - locking and minting tokens across chains -- **Transferring tokens with a payload** - including additional data with transfers - -### Attest a token - -Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. - -The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. - -```solidity -function attestToken( - address tokenAddress, - uint32 nonce -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `tokenAddress` ++"address"++ - - The contract address of the token to be attested. - - --- - - `nonce` ++"uint32"++ - - An arbitrary value provided by the caller to ensure uniqueness. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the attestation transaction. - -When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. - -You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. - -### Transfer Tokens - -Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. - -Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. - -```solidity -function transferTokens( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint256 arbiterFee, - uint32 nonce -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `token` ++"address"++ - - The address of the token being transferred. - - --- - - `amount` ++"uint256"++ - The amount of tokens to be transferred. - - --- - - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. - - --- - - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. - - --- - - `arbiterFee` ++"uint256"++ - Optional fee to be paid to an arbiter for relaying the transfer. - - --- - - `nonce` ++"uint32"++ - A unique identifier for the transaction. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. - -Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. - -```solidity -function completeTransfer(bytes memory encodedVm) external; -``` - -??? interface "Parameters" - - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. - -!!!note - - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain - -### Transfer tokens with payload - -While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. - -Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. - -```solidity -function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `token` ++"address"++ - - The address of the token being transferred. - - --- - - `amount` ++"uint256"++ - The amount of tokens to be transferred. - - --- - - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. - - --- - - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. - - --- - - `nonce` ++"uint32"++ - A unique identifier for the transaction. - - --- - - `payload` ++"bytes memory"++ - Arbitrary data payload attached to the transaction. - -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. - -After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. - -Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. - -```solidity -function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); -``` - -??? interface "Parameters" - - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. - -??? interface "Returns" - - `bytes memory` - - The extracted payload data. - -## Source Code References - -For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: - -- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} -- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} - -## Portal Bridge - -A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/ ---- BEGIN CONTENT --- ---- -title: Multichain Transfers -description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -categories: Transfer ---- - -# Multichain Transfers - -These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. - -Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: - -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset -- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism - -## Compare Transfer Products - -A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: - -### NTT vs. Token Bridge - -Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. - -- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains -- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases - -
    - -| Supports | NTT | Token Bridge | -|---------------------------|--------------------|--------------------| -| Message Payload | :white_check_mark: | :white_check_mark: | -| Wrapped Assets | :x: | :white_check_mark: | -| Native Assets | :white_check_mark: | :x: | -| Contract-Free Development | :x: | :white_check_mark: | -| User-Owned Contracts | :white_check_mark: | :x: | - -
    - -In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: - -
    - - -### Settlement - -Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. - -By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. - -## Additional Resources - -
    - -- :octicons-tools-16:{ .lg .middle } **Product Comparison** - - --- - - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - - [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) - -- :octicons-book-16:{ .lg .middle } **Use Cases** - - --- - - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. - - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) - - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Circle's CCTP Bridge -description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -categories: Transfer ---- - -# Circle's CCTP Bridge - -Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. - -While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: - -- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves -- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain -- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer - -!!! note - Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. - -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. - -## Automatic Relaying - -To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. - -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. - -The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. - -| Chain | Fee | -|:---------------:|:---------------:| -| Ethereum | 1.0 USDC | -| Everything else | 0.1 USDC | - - - -## Native Gas Drop Off - -Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. - -The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. - - ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- - -# Deployment Models - -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. - -## Hub-and-Spoke - -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. - -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. - -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain - -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. - -## Burn-and-Mint - -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. - -This model best suits new token deployments or projects willing to upgrade existing contracts. - -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- - -# Native Token Transfers - -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. - - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} - -## Introduction - -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. - -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. - -## Key Features - -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: - -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds - -## Integration Paths - -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. - -### Native Token Transfers Framework - -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. - -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments - -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: - -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} - -### Token Bridge - -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. - -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains - -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. - -## Supported Token Standards - -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- - -# Wormhole Settlement Overview - -## Introduction - -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. - -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. - -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. - -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. - -## Key Features - -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake - -## Integrator Paths - -### SDK Integrators - -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. - -### NTT Integrators - -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. - -### Chain Integrators - -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. - -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. - -## Related Resources - -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ ---- BEGIN CONTENT --- ---- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer ---- - -# Token Bridge - -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. - -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. - -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. - -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. - -### How Does It Work? - -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. - -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. - -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. - -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). - -### Token Transfer Flow - -The transfer process is simple yet secure, involving a few key steps: - -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody - -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) - -### Key Features of the Token Bridge - -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. - -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. - -### Message and Payload Structure - -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. - -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract - -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. - -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. - -### Security and Authorization - -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. - -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. - -### Portal Bridge - -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ ---- BEGIN CONTENT --- ---- -title: Get Started with CCTP -description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. -categories: Transfer ---- - -# Get Started with CCTP - -## Introduction - -[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. - -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. - -You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. - -## Prerequisites - -Before you begin, make sure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} - - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} - -This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. - -## Configure Your Token Transfer Environment - -1. Create a new directory and initialize a Node.js project: - - ```bash - mkdir cctp-bridge - cd cctp-bridge - npm init -y - ``` - -2. Install the required dependencies: - - ```bash - npm install @wormhole-foundation/sdk - npm install -D tsx typescript - ``` - -3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: - - ```bash - touch transfer.ts helper.ts - ``` - -4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. - - !!! warning - If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. - -## Perform a CCTP Transfer - -This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. - -Start by defining utility functions for signer and token setup: - -1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: - - ```ts title="helper.ts" - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, -} from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import evm from '@wormhole-foundation/sdk/evm'; - -/** - * Returns a signer for the given chain using locally scoped credentials. - * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must - * be loaded securely beforehand, for example via a keystore, secrets - * manager, or environment variables (not recommended). - */ -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; - - switch (platform) { - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); - break; - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); - break; - default: - throw new Error(`Unsupported platform: ${platform}`); - } - - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - - ``` - -2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: - - ```ts title="transfer.ts" - import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helper'; - -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Grab chain Contexts -- these hold a reference to a cached rpc client - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); - - // Get signer from local key - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000n; - - const automatic = false; - - // Create the circleTransfer transaction (USDC-only) - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); - - const quote = await CircleTransfer.quoteTransfer( - sendChain, - rcvChain, - xfer.transfer - ); - console.log('Quote: ', quote); - - // Step 1: Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); - - // Step 2: Wait for Circle Attestation (VAA) - const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(timeout); - console.log(`Got Attestation: `, attestIds); - - // Step 3: Complete the transfer on the destination chain (Sepolia) - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, dstTxids); - - process.exit(0); -})(); - ``` - -3. Run the script to execute the transfer: - - ```bash - npx tsx transfer.ts - ``` - - You will see terminal output similar to the following: - -
    -npx tsx transfer.ts -Starting Transfer -Started Transfer: - [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', - '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] - -Waiting for Attestation -Retrying Circle:GetAttestation, attempt 0/60 -Retrying Circle:GetAttestation, attempt 1/60 - -Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] - -Completing Transfer -Completed Transfer: - [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] - -
    - -To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. - -## Next Steps - -Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: - - - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ ---- BEGIN CONTENT --- ---- -title: CCTP Bridge with Wormhole -description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. -categories: Transfer ---- - -# CCTP with Wormhole Overview - -The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. - -## Key Features - -- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. -- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. -- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. -- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. -- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. -- **Gas payment**: Covering destination gas in automated vs. manual transfers. - - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. - - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. - -## How It Works - -This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. - -1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. - -2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. - -3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. - -4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. - -5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. - -```mermaid -sequenceDiagram - participant User as Alice - participant SourceChain as Circle Bridge
    on Ethereum - participant Circle - participant Guardians as Wormhole Guardians - participant Relayer - participant DestinationChain as Circle Bridge
    on Avalanche - - User->>SourceChain: Submit transfer
    (100 USDC to Avalanche) - SourceChain->>Circle: Initiate a burn - Circle->>Circle: Burn USDC and provide attestation - SourceChain->>Guardians: Emit Wormhole message (transfer metadata) - Guardians->>Guardians: Sign message and produce VAA - Relayer->>Guardians: Fetch signed VAA - Relayer->>Circle: Fetch Circle burn attestation - Relayer->>DestinationChain: Submit VAA and
    attestation - DestinationChain->>Circle: Verify Circle attestation - Circle->>User: Mint USDC to Alice -``` - -!!! note - For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. - -## Use Cases - -Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: - -- **USDC Payments Across Chains** - - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. - - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. - - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. - -- **USDC-Powered Multichain Settlement** - - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. - - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. - -## Next Steps - -Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: - -- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. -- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. -- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ ---- BEGIN CONTENT --- ---- -title: Routes -description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -categories: Connect, Transfer ---- - -## Routes Overview {: #routes-overview} - -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. - -Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. - -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. - -## Token Bridge Routes {: #token-bridge-routes} - -The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. - -#### Manual Route {: #manual-route} - -The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. - -#### Automatic Route {: #automatic-route} - -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. - -## CCTP Routes (USDC) {: #cctp-routes-usdc} - -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. - -Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. - -#### Manual Route {: #manual-route-cctp} - -This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. - -#### Automatic Route {: #automatic-route-cctp} - -Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. - -## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} - -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. - -#### Manual Route {: #manual-route-ntt} - -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. - -#### Automatic Route {: #automatic-route-ntt} - -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. - -## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} - -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). - -#### Automatic Route {: #automatic-route-eth} - -Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. - -## USDT Bridge Route {: #usdt-bridge-route} - -Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. - -#### Automatic Route {: #automatic-route-usdt} - -Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. - -## tBTC Route {: #tbtc-route} - -You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). - -Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. - -#### Manual Route {: #manual-route-tbtc} - -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ ---- BEGIN CONTENT --- ---- -title: Connect Data Configuration -description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. -categories: Connect, Transfer ---- - -## Data Configuration - -This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - -## Get Started - -Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. - -=== "React integration" - - ```ts - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - } -} - - - ``` - -=== "Hosted integration" - - ```ts - import WormholeConnect, { - wormholeConnectHosted, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; - -const container = document.getElementById('bridge-container'); - -wormholeConnectHosted(container, { - config, -}); - ``` - -!!! note - The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. - -## Examples {: #examples } - -### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } - -Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. - -=== "Mainnet" - - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; - -function App() { - return ; -} - ``` - -=== "Testnet" - - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - // You can use Connect with testnet chains by specifying "network": - network: 'Testnet', - chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], - rpcs: { - Avalanche: 'https://rpc.ankr.com/avalanche_fuji', - BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', - }, -}; - -function App() { - return ; -} - ``` - -!!! note - For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. - -### Configuring Routes - -By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. - -#### Available Route Plugins - -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: - -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol - -In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. - -For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. - -#### Example: Offer Only CCTP Transfers - -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: - -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; - -; -``` - -#### Example: Offer All Default Routes and Third-Party Plugins - -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. - -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -import { myNttConfig } from './consts'; // Custom NTT configuration - -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; - -; +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; + +; ``` This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. @@ -5070,6 +3837,14 @@ categories: Connect, Transfer Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + ## Prerequisites Before you begin, make sure you have the following: @@ -5081,7 +3856,7 @@ Before you begin, make sure you have the following: - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) -## Install and Setup Project +## Install and Set Up Project 1. Clone the demo repository and navigate to the project directory: @@ -5156,13 +3931,89 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. +Use the following guides to configure your Connect instance: -For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/connect/guides/hosted-version/ +--- BEGIN CONTENT --- +--- +title: Integrate Connect via CDN +description: +categories: Connect, Transfer +--- + +# Integrate Connect via CDN + +[Wormhole Connect](/docs/products/connect/overview/){target=\_blank} is a prebuilt UI component that makes it easy to transfer tokens across chains. You can integrate it into any website using either React or a hosted version served via [jsDelivr](https://www.jsdelivr.com/){target=\_blank}. + +This guide focuses on using the hosted version—ideal for simpler setups or non-React environments. It includes everything you need to get started with just a few lines of code. + +If you're using React, refer to the [Get Started with Connect](/docs/products/connect/get-started/){target=\_blank} guide. + +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + +## Add Connect to Your Project Using the Hosted Version + +The hosted version uses pre-built packages (including React) served via jsDelivr from npm. To integrate it without using React directly, add the following to your JavaScript project: + +```js +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; + +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'bridge-container' not found"); +} + +wormholeConnectHosted(container); +``` + +You can provide config and theme parameters in a second function argument: + +```js +import { + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; + +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'connect' not found"); +} + +wormholeConnectHosted(container, { + config: { + rpcs: { + // ... + } + }, + theme: { + background: { + default: '#004547', + } + } +}); +``` + +## Next Steps + +Use the following guides to configure your Connect instance: + +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ --- BEGIN CONTENT --- --- @@ -5796,7 +4647,7 @@ Here are some key use cases that highlight the power and versatility of Connect: Add Connect to your app with these key setup steps: -[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/connect/overview/connect-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ @@ -6312,15 +5163,40 @@ While xERC20 is an extension of the ERC20 standard, NTT is designed as a framewo To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. -## Is there a way to use NTT tokens with chains that don't currently support NTT? +## Is there a way to use NTT tokens with chains that don't currently support NTT? + +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: + +- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) +- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism +- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT + +This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. + +## How can I update my NTT CLI version? + +To update an existing NTT CLI installation, run the following command in your terminal: + +```bash +ntt update +``` + +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. + +For local development, you can update your CLI version from a specific branch or install from a local path. + +To install from a specific branch, run: -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +```bash +ntt update --branch foo +``` -- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) -- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism -- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` -This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ @@ -6872,581 +5748,927 @@ If you want to use hub-and-spoke, skip this section and proceed to [Deploy and C Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. -Follow these steps to set the mint authority using the NTT CLI: +Follow these steps to set the mint authority using the NTT CLI: + +1. **Derive the token authority** - generate the PDA, which will manage token minting + + ```bash + ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR + ``` + +2. **Set SPL token mint authority** - delegate minting control to the derived PDA + + ```bash + spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA + ``` + +## Deploy and Configure NTT + +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + + +After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: + +1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: + + === "Burn-and-Mint" + + ```bash + ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` + + === "Hub-and-Spoke" + + ```bash + ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` + + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. + +2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: + + ```bash + ntt status + ``` + + If needed, sync your local configuration with the on-chain state: + + ```bash + ntt pull + ``` + +3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. + + Open your `deployment.json` file and adjust the values based on your use case: + + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + }, + "outbound": { + "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia + } + ``` + +4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees + + ```bash + ntt push --payer INSERT_YOUR_KEYPAIR_JSON + ``` + +### Troubleshoot Deployment Issues + +If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. + +## Where to Go Next + +
    + +- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** + + --- + + After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. + + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + +- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** + + --- + + Follow the NTT Post Deployment Guide for integration examples and testing instructions. + + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + +- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** + + --- + + Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. + + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} + +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + +
    +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +--- BEGIN CONTENT --- +--- +title: Deploy Native Token Transfers with Launchpad +description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +categories: NTT, Transfer +--- + +# Deploy Native Token Transfers with Launchpad + +## Introduction + +The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. + +Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. + +The Launchpad automates deployment, reducing complexity and saving time. + +This guide covers: + + - Launching a new cross-chain token + - Expanding an existing token for NTT + - Managing tokens via the dashboard and settings + +## Prerequisites + + - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) + - Minimum ETH (or equivalent) for gas fees per deployment + +## Supported Blockchains + +The NTT Launchpad currently supports deployments on the following mainnet chains: + + - Ethereum + - Arbitrum One + - Base + - Berachain + - Blast + - BNB Smart Chain + - Ink + - Optimism Mainnet + - Polygon + +## Choose Your Path + +Once ready, choose an option to proceed: + + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains + - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + +## Launch a Cross-Chain Token + +Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: + +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Launch a Cross-Chain Token** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) + +3. Set the token details: + 1. Select the **home network** from the dropdown menu + 2. Enter the **name** for the token + 3. Enter the **symbol** of the token + 4. Provide the **initial supply** + 5. To the token details, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) + +4. Select the deployment chains: + 1. The home network where your token will be deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) + +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step + +8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. + +## Expand Your Existing Token + +Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: + +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Expand Your Existing Token** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) + +3. Enter the token details: + 1. Choose the home network where your token is already deployed (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) + +4. Select the chains to deploy your token to: + 1. The home network where your token is already deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 1. Click **Next** + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet + + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -1. **Derive the token authority** - generate the PDA, which will manage token minting +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step - ```bash - ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR - ``` +8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details -2. **Set SPL token mint authority** - delegate minting control to the derived PDA +## Explore the Launchpad Dashboard - ```bash - spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA - ``` +To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. -## Deploy and Configure NTT +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) -!!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. +The dashboard provides a high-level view of your token across all deployed chains, including: + - Token addresses for each chain + - Supply distribution visualization + - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) -1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: +## Settings - === "Burn-and-Mint" +The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. - ```bash - ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` +### Chain Management - === "Hub-and-Spoke" +Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. - ```bash - ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` +From this section, you can also: - You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. + - **Pause the token** – temporarily turn off transfers on the selected chain + - **Deploy to a new chain** – expand your token by deploying it to an additional chain -2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) - ```bash - ntt status - ``` +### Role Management - If needed, sync your local configuration with the on-chain state: +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - ```bash - ntt pull - ``` + - **Manager’s Owner** – the owner through the `NTTOwner` proxy + - **Pauser** – the address authorized to pause transfers -3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) - Open your `deployment.json` file and adjust the values based on your use case: +### Security Threshold - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - }, - "outbound": { - "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia - } - ``` +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. -4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees +A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - ```bash - ntt push --payer INSERT_YOUR_KEYPAIR_JSON - ``` + - **Registered Transceivers** – displays the number of registered transceivers and their addresses + - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) -## Where to Go Next +### Peer Chains Limits -
    +Define the transfer restrictions for each connected network. You can adjust: -- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** + - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain + - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains - --- +Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. - After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) +--- END CONTENT --- - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/post-deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer +--- -- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** +# Native Token Transfers Post Deployment - --- +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - Follow the NTT Post Deployment Guide for integration examples and testing instructions. +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} +## Manual Relaying for Solana Transfers -- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. - --- +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. - Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. +## Where to Go Next - [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} +
    -- :octicons-question-16:{ .lg .middle } **View FAQs** +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** --- - Find answers to common questions about NTT. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) -- :octicons-question-16:{ .lg .middle } **View FAQs** +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** --- - Find answers to common questions about NTT. + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk)
    --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/troubleshoot/ --- BEGIN CONTENT --- --- -title: Deploy Native Token Transfers with Launchpad -description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +title: Troubleshooting NTT Deployment +description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. categories: NTT, Transfer --- -# Deploy Native Token Transfers with Launchpad +# Troubleshoot Your NTT Deployment -## Introduction +If you encounter issues during the NTT deployment process, check the following common points: -The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} + - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** + - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain +- **Mint authority transfer** + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} +- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file -Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. + ???- interface "Dockerfile" -The Launchpad automates deployment, reducing complexity and saving time. + ```Dockerfile + FROM ubuntu:20.04 + # Set environment variables to prevent interactive prompts during installation + ENV DEBIAN_FRONTEND=noninteractive -This guide covers: + # Update and install necessary dependencies + RUN apt-get update && apt-get install -y \ + curl \ + wget \ + git \ + build-essential \ + libssl-dev \ + libudev-dev \ + pkg-config \ + python3 \ + python3-pip \ + software-properties-common \ + ca-certificates \ + unzip \ + clang \ + cmake \ + protobuf-compiler \ + && apt-get clean && rm -rf /var/lib/apt/lists/* - - Launching a new cross-chain token - - Expanding an existing token for NTT - - Managing tokens via the dashboard and settings + # Install Rust + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + ENV PATH="/root/.cargo/bin:$PATH" -## Prerequisites + # Install Solana CLI ({{ntt.solana_cli_version}}) + RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" + ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" - - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) - - Minimum ETH (or equivalent) for gas fees per deployment + # Install Anchor using avm + RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ + && avm install 0.29.0 \ + && avm use 0.29.0 + ENV PATH="/root/.avm/bin:$PATH" -## Supported Blockchains -The NTT Launchpad currently supports deployments on the following mainnet chains: + ENV NVM_DIR=/root/.nvm + RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ + && . "$NVM_DIR/nvm.sh" \ + && nvm install 22 \ + && nvm use 22 \ + && nvm alias default 22 + ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" - - Ethereum - - Arbitrum One - - Base - - Berachain - - Blast - - BNB Smart Chain - - Ink - - Optimism Mainnet - - Polygon + # Install Bun + RUN curl -fsSL https://bun.sh/install | bash + ENV PATH="/root/.bun/bin:$PATH" -## Choose Your Path + # Install Foundry + RUN curl -L https://foundry.paradigm.xyz | bash + ENV PATH="/root/.foundry/bin:${PATH}" + RUN /bin/bash -c "source /root/.bashrc && foundryup" -Once ready, choose an option to proceed: + # Install Wormhole NTT CLI + RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + # Add a default working directory + WORKDIR /app -## Launch a Cross-Chain Token + # Expose port for development if needed + EXPOSE 8899 -Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: + # Entry point for the container + CMD ["bash"] + ``` -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + ???- interface "docker-compose.yml" + ```yml + services: + portal-ntt: + build: + context: . + dockerfile: Dockerfile + platform: linux/amd64 + volumes: + - ./src:/app + working_dir: /app + tty: true + ``` +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer +--- - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) - -2. Select **Launch a Cross-Chain Token** +## Native Token Transfers Overview - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. -3. Set the token details: - 1. Select the **home network** from the dropdown menu - 2. Enter the **name** for the token - 3. Enter the **symbol** of the token - 4. Provide the **initial supply** - 5. To the token details, click **Next** +## Key Features - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps -4. Select the deployment chains: - 1. The home network where your token will be deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) +## Deployment Models -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction +NTT offers two operational modes for your existing tokens: - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +## Supported Token Standards - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. -8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. -## Expand Your Existing Token +## Deployment Process -Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: +Here's a breakdown of the key steps involved when deploying NTT: -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) +## Use Cases -2. Select **Expand Your Existing Token** +- **Cross-Chain Swaps and Liquidity Aggregation** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution -3. Enter the token details: - 1. Choose the home network where your token is already deployed (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** +- **Borrowing and Lending Across Chains** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time -4. Select the chains to deploy your token to: - 1. The home network where your token is already deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 1. Click **Next** +- **Gas Abstraction** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction +- **Cross-Chain Payment Widgets** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +- **Cross-Chain Staking** - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +## Next Steps -8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details +Follow these steps to get started with NTT: -## Explore the Launchpad Dashboard +[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] +--- END CONTENT --- -To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +--- BEGIN CONTENT --- +--- +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer +--- -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) +# NTT CLI Commands -The dashboard provides a high-level view of your token across all deployed chains, including: +## Introduction - - Token addresses for each chain - - Supply distribution visualization - - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) +If you haven't installed the NTT CLI yet, follow the [NTT Installation](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank} instructions to set it up before proceeding. -## Settings +## Table of Commands -The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. +The following table lists the available NTT CLI commands, descriptions, and examples. -### Chain Management +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. -Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. +### General Commands -From this section, you can also: +| Command | Description | Example | +|-----------------------------------------|--------------------------------------------------------|--------------------------------------------------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest` | +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0` | +| `ntt clone
    ` | initialize a deployment file from an existing contract | `ntt clone Mainnet Solana Sol5678...` | +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain +### Configuration Commands -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) +| Command | Description | Example | +|----------------------------------------------|-----------------------------------------|------------------------------------------------| +| `ntt config set-chain ` | set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key` | +| `ntt config unset-chain ` | unset a configuration value for a chain | `ntt config unset-chain Ethereum scan_api_key` | +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key` | -### Role Management +### Solana Commands -This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +| Command | Description | Example | +|------------------------------------------------|----------------------------------------------------------|-------------------------------------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json` | +| `ntt solana token-authority ` | print the token authority address for a given program ID | `ntt solana token-authority Sol1234...` | +| `ntt solana ata ` | print the token authority address for a given program ID | `ntt solana ata Mint123... Owner123... token22` | - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers +## Where to Go Next -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) +
    -### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +- :octicons-gear-16:{ .lg .middle } **Configure NTT** -A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. + --- - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) -### Peer Chains Limits +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -Define the transfer restrictions for each connected network. You can adjust: + --- - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) +
    --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/managers-transceivers/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Overview -description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. categories: NTT, Transfer --- -## Native Token Transfers Overview +# Managers and Transceivers -Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. +## Managers -## Key Features +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) + ``` -## Deployment Models +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer -NTT offers two operational modes for your existing tokens: + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected -## Supported Token Standards + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner + ``` -Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. +## Transceivers -The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: -NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -## Deployment Process + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -Here's a breakdown of the key steps involved when deploying NTT: +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -## Use Cases +## Lifecycle of a Message -- **Cross-Chain Swaps and Liquidity Aggregation** +### EVM + +#### Transfer + +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. + +**Events** + +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); +``` + +#### Rate Limit + +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. + +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. + +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. -- **Borrowing and Lending Across Chains** +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time +**Events** -- **Gas Abstraction** +```ts +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); +``` - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` -- **Cross-Chain Payment Widgets** +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens +#### Send -- **Cross-Chain Staking** +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. -## Next Steps +**Events** -Follow these steps to get started with NTT: +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` -[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] ---- END CONTENT --- +#### Receive -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ ---- BEGIN CONTENT --- ---- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer ---- +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. -# NTT CLI Commands +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. -## Introduction +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. -## Table of Commands +**Events** -The following table lists the available NTT CLI commands, descriptions, and examples. +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` -### General Commands +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
    ` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | +#### Mint or Unlock -### Configuration Commands +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| +**Events** -### Solana Commands +```ts +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); +``` -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| +### Solana -## Where to Go Next +#### Transfer -
    +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -- :octicons-gear-16:{ .lg .middle } **Configure NTT** +Depending on the mode and instruction, the following will be produced in the program logs: - --- +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. - [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) +#### Rate Limit -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. - --- +If the transfer amount fits within the current capacity: - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +If the transfer amount doesn't fit within the current capacity: -
    ---- END CONTENT --- +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ ---- BEGIN CONTENT --- ---- -title: Troubleshooting NTT Deployment -description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. -categories: NTT, Transfer ---- +#### Send -# Troubleshooting NTT Deployment +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. -If you encounter issues during the NTT deployment process, check the following common points: +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain -- **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} -- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. - ???- interface "Dockerfile" +The following will be produced in the program logs: - ```Dockerfile - FROM ubuntu:20.04 - # Set environment variables to prevent interactive prompts during installation - ENV DEBIAN_FRONTEND=noninteractive +```ts +Program log: Instruction: ReleaseOutbound +``` - # Update and install necessary dependencies - RUN apt-get update && apt-get install -y \ - curl \ - wget \ - git \ - build-essential \ - libssl-dev \ - libudev-dev \ - pkg-config \ - python3 \ - python3-pip \ - software-properties-common \ - ca-certificates \ - unzip \ - clang \ - cmake \ - protobuf-compiler \ - && apt-get clean && rm -rf /var/lib/apt/lists/* +#### Receive - # Install Rust - RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - ENV PATH="/root/.cargo/bin:$PATH" +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. - # Install Solana CLI ({{ntt.solana_cli_version}}) - RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" - ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. - # Install Anchor using avm - RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ - && avm install 0.29.0 \ - && avm use 0.29.0 - ENV PATH="/root/.avm/bin:$PATH" +The following will be produced in the program logs: +```ts +Program log: Instruction: ReceiveMessage +``` - ENV NVM_DIR=/root/.nvm - RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install 22 \ - && nvm use 22 \ - && nvm alias default 22 - ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - # Install Bun - RUN curl -fsSL https://bun.sh/install | bash - ENV PATH="/root/.bun/bin:$PATH" +The following will be produced in the program logs: - # Install Foundry - RUN curl -L https://foundry.paradigm.xyz | bash - ENV PATH="/root/.foundry/bin:${PATH}" - RUN /bin/bash -c "source /root/.bashrc && foundryup" +```ts +Program log: Instruction: Redeem +``` - # Install Wormhole NTT CLI - RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash +#### Mint or Unlock - # Add a default working directory - WORKDIR /app +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. - # Expose port for development if needed - EXPOSE 8899 +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. - # Entry point for the container - CMD ["bash"] - ``` +Depending on the mode and instruction, the following will be produced in the program logs: - ???- interface "docker-compose.yml" - ```yml - services: - portal-ntt: - build: - context: . - dockerfile: Dockerfile - platform: linux/amd64 - volumes: - - ./src:/app - working_dir: /app - tty: true - ``` +```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock +``` --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -7469,7 +6691,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -7498,6 +6720,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -8346,462 +7572,324 @@ Updating the metadata (such as the token image, name, or symbol) of a wrapped to To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/token-bridge-contracts/ --- BEGIN CONTENT --- --- -title: Token Bridge Overview -description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +title: Get Started with Token Bridge +description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. categories: Token-Bridge, Transfer --- -# Token Bridge Overview +# Interact with Token Bridge Contracts -The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. +## Introduction -This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -## Key Features +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. -Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: +## Prerequisites -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +To interact with the Wormhole Token Bridge, you'll need the following: -## How It Works +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers -The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: +## How to Interact with Token Bridge Contracts -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +The primary functions of the Token Bridge contracts revolve around: -This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. +- **Attesting a token** - registering a new token for cross-chain transfers +- **Transferring tokens** - locking and minting tokens across chains +- **Transferring tokens with a payload** - including additional data with transfers -```mermaid -sequenceDiagram - participant Alice - participant Ethereum - participant GuardianNetwork - participant Solana +### Attest a token - Alice->>Ethereum: Lock ETH in Token Bridge contract - Ethereum->>GuardianNetwork: Emit transfer message - GuardianNetwork->>GuardianNetwork: Verify and sign message +Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. - GuardianNetwork->>Solana: Submit signed message - Solana->>Solana: Verify message and mint wrapped ETH (WETH) +The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. - Solana->>Alice: Deliver wrapped ETH on Solana +```solidity +function attestToken( + address tokenAddress, + uint32 nonce +) external payable returns (uint64 sequence); ``` -For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. - -## Use Cases - -Here are key use cases that highlight the power and versatility of the Token Bridge. - -- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards - -- **Tokenized Gaming Rewards** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains - -- **Multichain DeFi Arbitrage** - - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms - -## Next Steps - -If you are looking for more guided practice, take a look at: - -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge ---- END CONTENT --- - -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - +??? interface "Parameters" -
    -
    + `tokenAddress` ++"address"++ + + The contract address of the token to be attested. -## Cross-Chain Perpetuals + --- -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. + `nonce` ++"uint32"++ -
    -
    + An arbitrary value provided by the caller to ensure uniqueness. -🛠 **Wormhole products used:** +??? interface "Returns" -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences + `sequence` ++"uint64"++ + + A unique identifier for the attestation transaction. -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives +When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. -
    -
    +You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. +### Transfer Tokens -
    -
    +Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. -## Gas Abstraction +Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. +```solidity +function transferTokens( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint256 arbiterFee, + uint32 nonce +) external payable returns (uint64 sequence); +``` -
    -
    +??? interface "Parameters" -🛠 **Wormhole products used:** + `token` ++"address"++ + + The address of the token being transferred. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments + --- -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements + `amount` ++"uint256"++ + The amount of tokens to be transferred. -
    -
    + --- + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -
    -
    + --- -## Bridging Intent Library + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. + --- -
    -
    + `arbiterFee` ++"uint256"++ + Optional fee to be paid to an arbiter for relaying the transfer. -🛠 **Wormhole products used:** + --- -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents + `nonce` ++"uint32"++ + A unique identifier for the transaction. -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries +??? interface "Returns" -
    -
    + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. +Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. -
    -
    +```solidity +function completeTransfer(bytes memory encodedVm) external; +``` -## Multichain Prediction Markets +??? interface "Parameters" -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + `encodedVm` ++"bytes memory"++ + + The signed VAA containing the transfer details. -
    -
    +!!!note + - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation + - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -🛠 **Wormhole products used:** +### Transfer tokens with payload -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions +While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. -
    -
    +```solidity +function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload +) external payable returns (uint64 sequence); +``` +??? interface "Parameters" -
    -
    + `token` ++"address"++ + + The address of the token being transferred. -## Cross-Chain Payment Widgets + --- -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. + `amount` ++"uint256"++ + The amount of tokens to be transferred. -
    -
    + --- -🛠 **Wormhole products used:** + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers + --- -🔗 **Used in:** E-commerce, Web3 payments, and subscription models + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -
    -
    + --- + `nonce` ++"uint32"++ + A unique identifier for the transaction. -
    -
    + --- -## Oracle Networks + `payload` ++"bytes memory"++ + Arbitrary data payload attached to the transaction. -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. +??? interface "Returns" + + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. -
    -
    +After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. -🛠 **Wormhole products used:** +Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks +```solidity +function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); +``` -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} +??? interface "Parameters" -
    -
    + `encodedVm` ++"bytes memory"++ + The signed VAA containing the transfer details. -
    -
    +??? interface "Returns" -## Cross-Chain Staking + `bytes memory` -Enable users to stake assets on one chain while earning rewards or securing networks on another. + The extracted payload data. -
    -
    +## Source Code References -🛠 **Wormhole products used:** +For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks +- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} +- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} +## Portal Bridge -
    -
    +A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..learn/glossary/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer --- -# Glossary - -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. - -## Chain ID +# Token Bridge Overview -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. -## Consistency Level +## Key Features -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -## Delivery Provider +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +## How It Works -## Emitter +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain -## Finality +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana -## Guardian + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) -## Guardian Network + Solana->>Alice: Deliver wrapped ETH on Solana +``` -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. -## Guardian Set +## Use Cases -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +Here are key use cases that highlight the power and versatility of the Token Bridge. -## Heartbeat +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +- **Tokenized Gaming Rewards** -## Observation + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +- **Multichain DeFi Arbitrage** -## Relayer + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms -A relayer is any process that delivers VAAs to a destination. +## Next Steps -## Sequence +If you are looking for more guided practice, take a look at: -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +--- END CONTENT --- -## Spy +## Basics Concepts [shared: true] -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -## VAA +--- -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +## List of shared concept pages: -## Validator -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- @@ -9780,7 +8868,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -9809,6 +8897,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -9824,6 +8916,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 71d05020d..275a381ab 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -13,10 +13,10 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task - If unsure, respond with “Not specified in the documentation. ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/messaging/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/cli/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/dev-env.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/protocols-payloads.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/guides/sdk-layout.md [type: other] @@ -25,7 +25,314 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK +--- + +# Get Started with Messaging + +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions + +## Configure Your Messaging Environment + +1. Create a directory and initialize a Node.js project: + + ```bash + mkdir core-message + cd core-message + npm init -y + ``` + +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` + +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: + + ```bash + npm install @wormhole-foundation/sdk + ``` + +5. Create a new file named `main.ts`: + + ```bash + touch main.ts + ``` + +## Construct and Publish Your Message + +1. Open `main.ts` and update the code there as follows: + + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; + +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ + +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; + +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); + + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; + + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } + + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } + + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); + + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); + } + + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); + + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; + + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); + + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); + + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); + + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); + + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; + + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); + + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); + + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); + + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} + +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` + + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. + +2. Run the script using the following command: + + ```bash + npx tsx main.ts + ``` + + You will see terminal output similar to the following: + +
    +npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
    + +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages + +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + +## Next Steps + +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. + +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/tools/cli/get-started/ --- BEGIN CONTENT --- --- title: Wormhole CLI @@ -84,7 +391,7 @@ Options: ### Subcommands -??? code "Aptos" +??? interface "Aptos" ```bash worm aptos INSERT_COMMAND @@ -114,7 +421,7 @@ Options: --version Show version number [boolean] ``` -??? code "Edit VAA" +??? interface "Edit VAA" ```bash worm edit-vaa INSERT_COMMAND @@ -143,7 +450,7 @@ Options: --guardian-secret, --gs Guardian's secret key [string] ``` -??? code "EVM" +??? interface "EVM" ```bash worm evm INSERT_COMMAND @@ -166,7 +473,7 @@ Options: --rpc RPC endpoint [string] ``` -??? code "Generate" +??? interface "Generate" ```bash worm generate INSERT_COMMAND @@ -184,7 +491,7 @@ Options: -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] ``` -??? code "Info" +??? interface "Info" ```bash worm info INSERT_COMMAND @@ -212,7 +519,7 @@ Options: --version Show version number [boolean]
    ``` -??? code "NEAR" +??? interface "NEAR" ```bash worm near INSERT_COMMAND @@ -234,7 +541,7 @@ Options: -r, --rpc Override default rpc endpoint url [string] ``` -??? code "Parse" +??? interface "Parse" ```bash worm parse INSERT_VAA @@ -246,7 +553,7 @@ Options: --version Show version number [boolean] ``` -??? code "Recover" +??? interface "Recover" ```bash worm recover INSERT_DIGEST INSERT_SIGNATURE @@ -259,7 +566,7 @@ Options: --version Show version number [boolean] ``` -??? code "Status" +??? interface "Status" ```bash worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH @@ -332,7 +639,7 @@ Options: --version Show version number [boolean] ``` -??? code "Submit" +??? interface "Submit" ```bash worm submit INSERT_VAA @@ -411,7 +718,7 @@ Options: [boolean] [default: false] ``` -??? code "Sui" +??? interface "Sui" ```bash worm sui INSERT_COMMAND @@ -440,7 +747,7 @@ Options: --version Show version number [boolean] ``` -??? code "Transfer" +??? interface "Transfer" ```bash worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK @@ -565,7 +872,7 @@ Options: --rpc RPC endpoint [string] ``` -??? code "Verify VAA" +??? interface "Verify VAA" ```bash worm verify-vaa INSERT_VAA, INSERT_NETWORK @@ -576,10 +883,9 @@ Options: -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] ``` - ## Examples -### VAA generation +### Generate a VAA Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: @@ -603,7 +909,7 @@ worm generate attestation --emitter-chain ethereum \ --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 ``` -### VAA parsing +### Parse a VAA Use `parse` to parse a VAA into JSON: @@ -651,7 +957,7 @@ payload: { } ``` -### Submitting VAAs +### Submit VAAs Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): @@ -680,7 +986,7 @@ worm submit $(cat guardian-upgrade.txt) --network mainnet --chain celo The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. -### Getting Info +### Fetch Contract Information To get info about a contract (only EVM supported at this time), use the following command: @@ -763,8 +1069,6 @@ Running this command generates the following output: } ``` -### Additional Info Examples - You can get the contract address for a module as follows: ```bash @@ -777,6 +1081,8 @@ To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can worm info contract mainnet bsc NFTBridge ``` +### Fetch Chain Information + You can get the RPC address for a chain as follows: ```bash @@ -790,7 +1096,7 @@ worm info rpc mainnet bsc ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ +Doc-Content: https://wormhole.com/docs/tools/dev-env/ --- BEGIN CONTENT --- --- title: Local Dev Environment @@ -850,373 +1156,66 @@ https://api.testnet.wormholescan.io The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: -```text -https://api.wormholescan.io -``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ ---- BEGIN CONTENT --- ---- -title: Toolkit FAQs -description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. -categories: Solidity-SDK, Typescript-SDK ---- - -# Toolkit FAQs - -## Why does the `toNative` function in the TypeScript SDK return an error? - -The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. - -To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: - -```typescript -import solana from '@wormhole-foundation/sdk/solana'; -const wh = await wormhole('Testnet', [solana]); -``` - -## How can I retrieve the history of previously bridged transactions? - -To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: - -```bash -https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS -``` - -Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. - -???- example "Fetch transaction history for a specific address" - ```bash - curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" - ``` - -## How can I manually submit a VAA to a destination chain in the correct format? - -To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: - -1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format - - ```bash - https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced - ``` - -2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python - -3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) - - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section - - - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field - -Following these steps, you can manually submit a VAA in the proper format to a destination chain. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ ---- BEGIN CONTENT --- ---- -title: Get Started with Messaging -description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. -categories: Basics, Typescript-SDK ---- - -# Get Started with Messaging - -Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. - -## Prerequisites - -Before you begin, ensure you have the following: - -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed -- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed -- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) -- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network -- A private key for signing blockchain transactions - -## Configure Your Messaging Environment - -1. Create a directory and initialize a Node.js project: - - ```bash - mkdir core-message - cd core-message - npm init -y - ``` - -2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: - - ```bash - npm install --save-dev tsx typescript @types/node ethers - ``` - -3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: - - ```bash - npx tsc --init - ``` - - Make sure your `tsconfig.json` includes the following settings: - - ```json - { - "compilerOptions": { - // es2020 or newer - "target": "es2020", - // Use esnext if you configured your package.json with type: "module" - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } - } - ``` - -4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: - - ```bash - npm install @wormhole-foundation/sdk - ``` - -5. Create a new file named `main.ts`: - - ```bash - touch main.ts - ``` - -## Construct and Publish Your Message - -1. Open `main.ts` and update the code there as follows: - - ```ts title="main.ts" - import { - wormhole, - signSendWait, - toNative, - encoding, - type Chain, - type Network, - type NativeAddress, - type WormholeMessageId, - type UnsignedTransaction, - type TransactionId, - type WormholeCore, - type Signer as WormholeSdkSigner, - type ChainContext, -} from '@wormhole-foundation/sdk'; -// Platform-specific modules -import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; -import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; -import { - ethers, - Wallet, - JsonRpcProvider, - Signer as EthersSigner, -} from 'ethers'; - -/** - * The required value (SEPOLIA_PRIVATE_KEY) must - * be loaded securely beforehand, for example via a keystore, secrets - * manager, or environment variables (not recommended). - */ - -const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; -// Provide a private endpoint RPC URL for Sepolia, defaults to a public node -// if not set -const RPC_URL = - process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; - -async function main() { - // Initialize Wormhole SDK - const network = 'Testnet'; - const wh = await wormhole(network, [EvmPlatformLoader]); - console.log('Wormhole SDK Initialized.'); - - // Get the EVM signer and provider - let ethersJsSigner: EthersSigner; - let ethersJsProvider: JsonRpcProvider; - - try { - if (!SEPOLIA_PRIVATE_KEY) { - console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); - process.exit(1); - } - - ethersJsProvider = new JsonRpcProvider(RPC_URL); - const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); - ethersJsSigner = wallet.connect(ethersJsProvider); - console.log( - `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, - ); - } catch (error) { - console.error('Failed to get Ethers.js signer and provider:', error); - process.exit(1); - } - - // Define the source chain context - const sourceChainName: Chain = 'Sepolia'; - const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< - 'Testnet', - 'Sepolia', - 'Evm' - >; - console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); - - // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js - // signer using the Wormhole SDK's signing and transaction handling - // capabilities - let sdkSigner: WormholeSdkSigner; - try { - sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); - console.log( - `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, - ); - } catch (error) { - console.error('Failed to get Wormhole SDK Signer:', error); - process.exit(1); - } - - // Construct your message payload - const messageText = `HelloWormholeSDK-${Date.now()}`; - const payload: Uint8Array = encoding.bytes.encode(messageText); - console.log(`Message to send: "${messageText}"`); - - // Define message parameters - const messageNonce = Math.floor(Math.random() * 1_000_000_000); - const consistencyLevel = 1; - - try { - // Get the core protocol client - const coreProtocolClient: WormholeCore = - await sourceChainContext.getWormholeCore(); - - // Generate the unsigned transactions - const whSignerAddress: NativeAddress = toNative( - sdkSigner.chain(), - sdkSigner.address(), - ); - console.log( - `Preparing to publish message from ${whSignerAddress.toString()} on ${ - sourceChainContext.chain - }...`, - ); - - const unsignedTxs: AsyncGenerator> = - coreProtocolClient.publishMessage( - whSignerAddress, - payload, - messageNonce, - consistencyLevel, - ); +```text +https://api.wormholescan.io +``` +--- END CONTENT --- - // Sign and send the transactions - console.log( - 'Signing and sending the message publication transaction(s)...', - ); - const txIds: TransactionId[] = await signSendWait( - sourceChainContext, - unsignedTxs, - sdkSigner, - ); +Doc-Content: https://wormhole.com/docs/tools/faqs/ +--- BEGIN CONTENT --- +--- +title: Toolkit FAQs +description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. +categories: Solidity-SDK, Typescript-SDK +--- - if (!txIds || txIds.length === 0) { - throw new Error('No transaction IDs were returned from signSendWait.'); - } - const primaryTxIdObject = txIds[txIds.length - 1]; - const primaryTxid = primaryTxIdObject.txid; +# Toolkit FAQs - console.log(`Primary transaction ID for parsing: ${primaryTxid}`); - console.log( - `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, - ); +## Why does the `toNative` function in the TypeScript SDK return an error? - console.log( - '\nWaiting a few seconds for transaction to propagate before parsing...', - ); - await new Promise((resolve) => setTimeout(resolve, 8000)); +The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. - // Retrieve VAA identifiers - console.log( - `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, - ); - const messageIds: WormholeMessageId[] = - await sourceChainContext.parseTransaction(primaryTxid); +To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: - if (messageIds && messageIds.length > 0) { - const wormholeMessageId = messageIds[0]; - console.log('--- VAA Identifiers (WormholeMessageId) ---'); - console.log(' Emitter Chain:', wormholeMessageId.chain); - console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); - console.log(' Sequence:', wormholeMessageId.sequence.toString()); - console.log('-----------------------------------------'); - } else { - console.error( - `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, - ); - } - } catch (error) { - console.error( - 'Error during message publishing or VAA identifier retrieval:', - error, - ); - if (error instanceof Error && error.stack) { - console.error('Stack Trace:', error.stack); - } - } -} +```typescript +import solana from '@wormhole-foundation/sdk/solana'; +const wh = await wormhole('Testnet', [solana]); +``` -main().catch((e) => { - console.error('Critical error in main function (outer catch):', e); - if (e instanceof Error && e.stack) { - console.error('Stack Trace:', e.stack); - } - process.exit(1); -}); - ``` +## How can I retrieve the history of previously bridged transactions? - This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. +To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: -2. Run the script using the following command: +```bash +https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS +``` + +Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. +???- example "Fetch transaction history for a specific address" ```bash - npx tsx main.ts + curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" ``` - You will see terminal output similar to the following: +## How can I manually submit a VAA to a destination chain in the correct format? -
    -npx tsx main.ts -Wormhole SDK Initialized. -Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 -Source chain context obtained for: Sepolia -Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 -Message to send: "HelloWormholeSDK-1748362375390" -Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... -Signing and sending the message publication transaction(s)... -Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 -View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 -Waiting a few seconds for transaction to propagate before parsing... -Attempting to parse VAA identifiers from transaction: - 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... ---- VAA Identifiers (WormholeMessageId) --- - Emitter Chain: Sepolia - Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 - Sequence: 1 ------------------------------------------ - -
    +To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: -3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages +1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format -Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. + ```bash + https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced + ``` -## Next Steps +2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. +3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) -- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section + + - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field + +Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/get-started/ @@ -3780,138 +3779,22 @@ While a specific `WormholeTransfer`, such as `TokenTransfer` or `CCTPTransfer`, To provide a more flexible and generic interface, the `Wormhole` class provides a method to produce a `RouteResolver` that can be configured with a set of possible routes to be supported. -The following section demonstrates setting up and validating a token transfer using Wormhole's routing system. - -```ts -const resolver = wh.resolver([ - routes.TokenBridgeRoute, // manual token bridge - routes.AutomaticTokenBridgeRoute, // automatic token bridge - routes.CCTPRoute, // manual CCTP - routes.AutomaticCCTPRoute, // automatic CCTP - routes.AutomaticPorticoRoute, // Native eth transfers - ]); -``` - -Once created, the resolver can be used to provide a list of input and possible output tokens. - -```ts -const srcTokens = await resolver.supportedSourceTokens(sendChain); - console.log( - 'Allowed source tokens: ', - srcTokens.map((t) => canonicalAddress(t)) - ); - - const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); - - // Given the send token, what can we possibly get on the destination chain? - const destTokens = await resolver.supportedDestinationTokens( - sendToken, - sendChain, - destChain - ); - console.log( - 'For the given source token and routes configured, the following tokens may be receivable: ', - destTokens.map((t) => canonicalAddress(t)) - ); - // Grab the first one for the example - const destinationToken = destTokens[0]!; -``` - -Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfill the request. Creating a transfer request fetches the token details since all routes will need to know about the tokens. - -```ts -// Since all routes will need to know about the tokens - const tr = await routes.RouteTransferRequest.create(wh, { - source: sendToken, - destination: destinationToken, - }); - - // Resolve the transfer request to a set of routes that can perform it - const foundRoutes = await resolver.findRoutes(tr); - console.log( - 'For the transfer parameters, we found these routes: ', - foundRoutes - ); -``` - -Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - -After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. - -After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. - -```ts -'This route offers the following default options', - bestRoute.getDefaultOptions() - ); - - // Specify the amount as a decimal string - const amt = '0.001'; - // Create the transfer params for this request - const transferParams = { amount: amt, options: { nativeGas: 0 } }; - - // Validate the transfer params passed, this returns a new type of ValidatedTransferParams - // which (believe it or not) is a validated version of the input params - // This new var must be passed to the next step, quote - const validated = await bestRoute.validate(tr, transferParams); - if (!validated.valid) throw validated.error; - console.log('Validated parameters: ', validated.params); - - // Get a quote for the transfer, this too returns a new type that must - // be passed to the next step, execute (if you like the quote) - const quote = await bestRoute.quote(tr, validated.params); - if (!quote.success) throw quote.error; - console.log('Best route quote: ', quote); -``` - -Finally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`. - -```ts -tr, - sender.signer, - quote, - receiver.address - ); - console.log('Initiated transfer with receipt: ', receipt); -``` - -??? code "View the complete script" - - ```ts - import { - Wormhole, - canonicalAddress, - routes, - wormhole, -} from '@wormhole-foundation/sdk'; - -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/index.js'; - -(async function () { - // Setup - const wh = await wormhole('Testnet', [evm, solana]); - - // Get chain contexts - const sendChain = wh.getChain('Avalanche'); - const destChain = wh.getChain('Solana'); - - // Get signers from local config - const sender = await getSigner(sendChain); - const receiver = await getSigner(destChain); - - // Create new resolver, passing the set of routes to consider - const resolver = wh.resolver([ +The following section demonstrates setting up and validating a token transfer using Wormhole's routing system. + +```ts +const resolver = wh.resolver([ routes.TokenBridgeRoute, // manual token bridge routes.AutomaticTokenBridgeRoute, // automatic token bridge routes.CCTPRoute, // manual CCTP routes.AutomaticCCTPRoute, // automatic CCTP routes.AutomaticPorticoRoute, // Native eth transfers ]); +``` - // What tokens are available on the source chain? - const srcTokens = await resolver.supportedSourceTokens(sendChain); +Once created, the resolver can be used to provide a list of input and possible output tokens. + +```ts +const srcTokens = await resolver.supportedSourceTokens(sendChain); console.log( 'Allowed source tokens: ', srcTokens.map((t) => canonicalAddress(t)) @@ -3931,9 +3814,12 @@ import { getSigner } from './helpers/index.js'; ); // Grab the first one for the example const destinationToken = destTokens[0]!; +``` - // Creating a transfer request fetches token details - // Since all routes will need to know about the tokens +Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfill the request. Creating a transfer request fetches the token details since all routes will need to know about the tokens. + +```ts +// Since all routes will need to know about the tokens const tr = await routes.RouteTransferRequest.create(wh, { source: sendToken, destination: destinationToken, @@ -3945,12 +3831,16 @@ import { getSigner } from './helpers/index.js'; 'For the transfer parameters, we found these routes: ', foundRoutes ); +``` - const bestRoute = foundRoutes[0]!; - console.log('Selected: ', bestRoute); +Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - console.log( - 'This route offers the following default options', +After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. + +After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. + +```ts +'This route offers the following default options', bestRoute.getDefaultOptions() ); @@ -3971,430 +3861,179 @@ import { getSigner } from './helpers/index.js'; const quote = await bestRoute.quote(tr, validated.params); if (!quote.success) throw quote.error; console.log('Best route quote: ', quote); - - // If you're sure you want to do this, set this to true - const imSure = false; - if (imSure) { - // Now the transfer may be initiated - // A receipt will be returned, guess what you gotta do with that? - const receipt = await bestRoute.initiate( - tr, - sender.signer, - quote, - receiver.address - ); - console.log('Initiated transfer with receipt: ', receipt); - - // Kick off a wait log, if there is an opportunity to complete, this function will do it - // See the implementation for how this works - await routes.checkAndCompleteTransfer(bestRoute, receipt, receiver.signer); - } else { - console.log('Not initiating transfer (set `imSure` to true to do so)'); - } -})(); - ``` - -See the `router.ts` example in the [examples directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/examples){target=\_blank} for a full working example. - -### Routes as Plugins - -Routes can be imported from any npm package that exports them and configured with the resolver. Custom routes must extend [`Route`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L21-L64){target=\_blank} and implement [`StaticRouteMethods`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L101){target=\_blank}. - -```ts -import { Network, routes } from '@wormhole-foundation/sdk-connect'; - -export class CustomRoute - extends routes.Route - implements routes.StaticRouteMethods -{ - static meta = { - name: 'CustomRoute', - }; - // implementation... -} - ``` -A noteworthy example of a route exported from a separate npm package is Wormhole Native Token Transfers (NTT). See the [`NttAutomaticRoute`](https://github.com/wormhole-foundation/native-token-transfers/blob/66f8e414223a77f5c736541db0a7a85396cab71c/sdk/route/src/automatic.ts#L48){target=\_blank} route implementation. - -## See Also - -The TSdoc is available [on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank}. ---- END CONTENT --- - -## Basics Concepts [shared: true] - -The following section contains foundational documentation shared across all Wormhole products. -It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. -This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. -This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. - ---- - -## List of shared concept pages: - - -## Full content for shared concepts: - -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- - -# Wormhole Use Cases - -
    -
    - -## Cross-Chain Swaps and Liquidity Aggregation - -Enable seamless swaps between chains with real-time liquidity routing. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution - -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} - -
    -
    - - -
    -
    - -## Borrowing and Lending Across Chains - -Let users borrow assets on one chain using collateral from another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time - -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} - -
    -
    - - -
    -
    - -## Real-Time Price Feeds and Trading Strategies - -Fetch price feeds across multiple chains for DeFi applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades - -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} - -
    -
    - - -
    -
    - -## Asset Movement Between Bitcoin and Other Chains - -Enable direct BTC transfers without wrapped assets. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains - -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} - -
    -
    - -
    -
    - -## Decentralized Social Platforms - -Enable seamless communication and asset transfer across decentralized social networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards - -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} - -
    -
    - - -
    -
    - -## Memecoin Launchpads - -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes - -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals - -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences - -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives - -
    -
    - - -
    -
    - -## Gas Abstraction - -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments - -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements - -
    -
    - - -
    -
    - -## Bridging Intent Library - -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents - -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries - -
    -
    - - -
    -
    - -## Multichain Prediction Markets - -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions - -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming - -
    -
    - - -
    -
    - -## Cross-Chain Payment Widgets - -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers - -🔗 **Used in:** E-commerce, Web3 payments, and subscription models - -
    -
    - - -
    -
    - -## Oracle Networks - -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks - -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} - -
    -
    - - -
    -
    - -## Cross-Chain Staking - -Enable users to stake assets on one chain while earning rewards or securing networks on another. - -
    -
    - -🛠 **Wormhole products used:** - -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks - -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} - -
    -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/..learn/glossary/ ---- BEGIN CONTENT --- ---- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics ---- +Finally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`. -# Glossary +```ts +tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); +``` -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +??? code "View the complete script" -## Chain ID + ```ts + import { + Wormhole, + canonicalAddress, + routes, + wormhole, +} from '@wormhole-foundation/sdk'; -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/index.js'; -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +(async function () { + // Setup + const wh = await wormhole('Testnet', [evm, solana]); -## Consistency Level + // Get chain contexts + const sendChain = wh.getChain('Avalanche'); + const destChain = wh.getChain('Solana'); -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + // Get signers from local config + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); -## Delivery Provider + // Create new resolver, passing the set of routes to consider + const resolver = wh.resolver([ + routes.TokenBridgeRoute, // manual token bridge + routes.AutomaticTokenBridgeRoute, // automatic token bridge + routes.CCTPRoute, // manual CCTP + routes.AutomaticCCTPRoute, // automatic CCTP + routes.AutomaticPorticoRoute, // Native eth transfers + ]); -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + // What tokens are available on the source chain? + const srcTokens = await resolver.supportedSourceTokens(sendChain); + console.log( + 'Allowed source tokens: ', + srcTokens.map((t) => canonicalAddress(t)) + ); -## Emitter + const sendToken = Wormhole.tokenId(sendChain.chain, 'native'); -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + // Given the send token, what can we possibly get on the destination chain? + const destTokens = await resolver.supportedDestinationTokens( + sendToken, + sendChain, + destChain + ); + console.log( + 'For the given source token and routes configured, the following tokens may be receivable: ', + destTokens.map((t) => canonicalAddress(t)) + ); + // Grab the first one for the example + const destinationToken = destTokens[0]!; -## Finality + // Creating a transfer request fetches token details + // Since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source: sendToken, + destination: destinationToken, + }); -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + console.log( + 'For the transfer parameters, we found these routes: ', + foundRoutes + ); -## Guardian + const bestRoute = foundRoutes[0]!; + console.log('Selected: ', bestRoute); -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + console.log( + 'This route offers the following default options', + bestRoute.getDefaultOptions() + ); -## Guardian Network + // Specify the amount as a decimal string + const amt = '0.001'; + // Create the transfer params for this request + const transferParams = { amount: amt, options: { nativeGas: 0 } }; -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + // Validate the transfer params passed, this returns a new type of ValidatedTransferParams + // which (believe it or not) is a validated version of the input params + // This new var must be passed to the next step, quote + const validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) throw validated.error; + console.log('Validated parameters: ', validated.params); -## Guardian Set + // Get a quote for the transfer, this too returns a new type that must + // be passed to the next step, execute (if you like the quote) + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) throw quote.error; + console.log('Best route quote: ', quote); -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + // If you're sure you want to do this, set this to true + const imSure = false; + if (imSure) { + // Now the transfer may be initiated + // A receipt will be returned, guess what you gotta do with that? + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); -## Heartbeat + // Kick off a wait log, if there is an opportunity to complete, this function will do it + // See the implementation for how this works + await routes.checkAndCompleteTransfer(bestRoute, receipt, receiver.signer); + } else { + console.log('Not initiating transfer (set `imSure` to true to do so)'); + } +})(); + ``` -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +See the `router.ts` example in the [examples directory](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/examples){target=\_blank} for a full working example. -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +### Routes as Plugins -## Observation +Routes can be imported from any npm package that exports them and configured with the resolver. Custom routes must extend [`Route`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L21-L64){target=\_blank} and implement [`StaticRouteMethods`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/0c57292368146c460abc9ce9e7f6a42be8e0b903/connect/src/routes/route.ts#L101){target=\_blank}. -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +```ts +import { Network, routes } from '@wormhole-foundation/sdk-connect'; -## Relayer +export class CustomRoute + extends routes.Route + implements routes.StaticRouteMethods +{ + static meta = { + name: 'CustomRoute', + }; + // implementation... +} + +``` -A relayer is any process that delivers VAAs to a destination. +A noteworthy example of a route exported from a separate npm package is Wormhole Native Token Transfers (NTT). See the [`NttAutomaticRoute`](https://github.com/wormhole-foundation/native-token-transfers/blob/66f8e414223a77f5c736541db0a7a85396cab71c/sdk/route/src/automatic.ts#L48){target=\_blank} route implementation. -## Sequence +## See Also -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +The TSdoc is available [on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank}. +--- END CONTENT --- -## Spy +## Basics Concepts [shared: true] -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +The following section contains foundational documentation shared across all Wormhole products. +It describes the architecture and messaging infrastructure that serve as the backbone for all integrations built with Wormhole. +This includes the core contracts, VAA (Verifiable Action Approval) structure, guardian set functionality, and message flow mechanisms. +This context is provided to help understand how the system works under the hood, but responses should stay focused on the specific product unless the user explicitly asks about the general architecture. -## VAA +--- -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +## List of shared concept pages: -## Validator -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Full content for shared concepts: Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- @@ -5373,7 +5012,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -5402,6 +5041,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI @@ -5417,6 +5060,83 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ +--- BEGIN CONTENT --- +--- +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics +--- + +# Glossary + +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. + +## Chain ID + +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. + +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. + +## Consistency Level + +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. + +## Delivery Provider + +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. + +## Emitter + +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. + +## Finality + +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. + +## Guardian + +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. + +## Guardian Network + +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. + +## Guardian Set + +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. + +## Heartbeat + +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. + +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. + +## Observation + +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. + +## Relayer + +A relayer is any process that delivers VAAs to a destination. + +## Sequence + +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. + +## Spy + +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. + +## VAA + +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. + +## Validator + +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/protocol/architecture/ --- BEGIN CONTENT --- --- diff --git a/llms-full.txt b/llms-full.txt index 1e2bea064..05fecb0bf 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -6,34 +6,10 @@ Wormhole. A cross-chain messaging protocol used to move data and assets between Documentation: https://wormhole.com/docs/ ## List of doc pages: -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/core-messaging/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/index.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/cctp-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md @@ -42,6 +18,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/hosted-version.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md @@ -71,9 +48,11 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/post-deployment.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/troubleshoot.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md @@ -89,6 +68,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/glossary.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md @@ -103,7 +83,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/token-bridge-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md @@ -117,6 +97,9 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/cli/get-started.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/dev-env.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md @@ -127,2376 +110,2319 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re ## Full content for each doc page -Doc-Content: https://wormhole.com/docs/..build/core-messaging/ +Doc-Content: https://wormhole.com/docs/ai-resources/ai-resources/ --- BEGIN CONTENT --- --- -title: Core Messaging Layer Contracts -description: Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. +title: AI Resources +description: Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. --- -# Core Messaging - -Wormhole-deployed relayers and Core Contracts are essential for sending and receiving multichain messages. Learning to work directly with these building blocks offers a deeper understanding of Wormhole and increased control and customization options. - -Follow the links below for how-to guides about using Core Contracts and Wormhole-deployed relayers to send, receive, validate, and track multichain messages. +# AI Resources +Wormhole provides `.txt` files containing the documentation content and navigation structure, optimized for use with large language models (LLMs) and AI tools. These resources help build AI assistants, power code search, or enable custom tooling trained on Wormhole’s docs. -## Simplified Message Flow +Each category file includes foundational content from the **Basics** and **Reference** categories to ensure LLMs have the necessary context. +## Download LLM Files -Wormhole-deployed relayer support is limited to EVM environments. For a complete list of supported EVM environment blockchains, see the [Supported Networks](/docs/products/reference/supported-networks/){target=\_blank} page. -[timeline(wormhole-docs/.snippets/text/build/core-messaging/core-messaging-timeline.json)] +| Category | Description | File | Actions | +|----------------|-------------------|-------|----------| +| Index | Navigation index of all Wormhole documentation pages | `llms.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms.txt" } [:octicons-download-16:](/docs/llms.txt){ download="llms.txt" } | +| Full Documentation | Full content of all documentation pages | `llms-full.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-full.txt" } [:octicons-download-16:](/docs/llms-full.txt){ download="llms-full.txt" } | +| Basics | Wormhole's architecture, security, and core components to help understand how the protocol works | `llms-basics.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-basics.txt" } [:octicons-download-16:](/docs/llms-files/llms-basics.txt){ download="llms-basics.txt" } | +| Reference | Reference details such as chain IDs, contract addresses, and finality levels | `llms-reference.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-reference.txt"} [:octicons-download-16:](/docs/llms-files/llms-reference.txt){ download="llms-reference.txt" } | +| NTT | All NTT docs, including architecture, deployment guides, CLI usage, and configuration for EVM and Solana | `llms-ntt.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-ntt.txt" } [:octicons-download-16:](/docs/llms-files/llms-ntt.txt){ download="llms-ntt.txt" } | +| Connect | Setup, features, and configuration details for integrating the Connect widget into your dApp | `llms-connect.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-connect.txt" } [:octicons-download-16:](/docs/llms-files/llms-connect.txt){ download="llms-connect.txt" } | +| Token Bridge | Architecture overview, transfer flows, and smart contract methods for cross-chain token transfers using the Token Bridge | `llms-token-bridge.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-token-bridge.txt" } [:octicons-download-16:](/docs/llms-files/llms-token-bridge.txt){ download="llms-token-bridge.txt" } | +| Settlement | Architecture, integration guides, and setup instructions for building on the Wormhole Settlement protocol | `llms-settlement.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-settlement.txt" } [:octicons-download-16:](/docs/llms-files/llms-settlement.txt){ download="llms-settlement.txt" } | +| Relayers | Guides and reference for using Wormhole’s Relayer module, building cross-chain messaging contracts, and running custom relayers | `llms-relayers.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-relayers.txt" } [:octicons-download-16:](/docs/llms-files/llms-relayers.txt){ download="llms-relayers.txt" } | +| MultiGov | Architecture, deployment steps, and upgrade instructions for multichain governance on EVM and Solana | `llms-multigov.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-multigov.txt" } [:octicons-download-16:](/docs/llms-files/llms-multigov.txt){ download="llms-multigov.txt" } | +| Queries | Guides for using the Wormhole Query SDK and Proxy to construct, test, and verify on-chain data queries across chains | `llms-queries.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-queries.txt" } [:octicons-download-16:](/docs/llms-files/llms-queries.txt){ download="llms-queries.txt" } | +| Solidity SDK | SDK docs for cross-chain messaging, token transfers, relayer integration, and local testing in Solidity | `llms-solidity-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-solidity-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-solidity-sdk.txt){ download="llms-solidity-sdk.txt" } | +| TypeScript SDK | Docs for working with VAAs, payloads, and cross-chain message structures using the TypeScript SDK | `llms-typescript-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-typescript-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-typescript-sdk.txt){ download="llms-typescript-sdk.txt" } | -## Next Steps +!!! note + The `llms-full.txt` file may exceed the input limits of some language models due to its size. If you encounter limitations, consider using the files by category. +--- END CONTENT --- -
    +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/concepts/integration/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -- :octicons-tools-16:{ .lg .middle} **Get Started with Core Contracts** +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with CCTP +description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. +categories: Transfer +--- - --- +# Get Started with CCTP - Follow this series of how-to guides about interacting with Core Contracts to send, receive, and validate messages. +## Introduction - [:custom-arrow: Get started](/docs/products/messaging/guides/core-contracts/#prerequisites) +[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. -- :octicons-tools-16:{ .lg .middle } **Get Started with Relayers** +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. - --- +You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. - Follow this series of how-to guides about using Wormhole-deployed relayers to send, receive, and track the progress of messages. +## Prerequisites - [:custom-arrow: Get started](/docs/products/messaging/guides/wormhole-relayers/#get-started-with-the-wormhole-relayer) +Before you begin, make sure you have the following: -
    ---- END CONTENT --- + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} -Doc-Content: https://wormhole.com/docs/..build/multigov/ ---- BEGIN CONTENT --- ---- -title: Getting Started with MultiGov -description: Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -categories: MultiGov ---- +This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. -# MultiGov +## Configure Your Token Transfer Environment -## Begin the MultiGov Integration Process +1. Create a new directory and initialize a Node.js project: -Take the following steps to get started with a MultiGov integration: + ```bash + mkdir cctp-bridge + cd cctp-bridge + npm init -y + ``` -1. Evaluate if [MultiGov](/docs/learn/governance/) meets your cross-chain governance needs -2. Fill out the intake form on the [Tally website](https://www.tally.xyz/get-started){target=\_blank} -3. The Tally team will review your application and contact you to discuss implementation details -4. Work with the Tally team to customize and deploy MultiGov for your specific use case +2. Install the required dependencies: -## Start Building + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` -
    +3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: -- :octicons-rocket-16:{ .lg .middle } **Deploy to EVM** + ```bash + touch transfer.ts helper.ts + ``` - --- +4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. - Set up and deploy MultiGov on EVM chains with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. - [:custom-arrow: Discover how to deploy MultiGov](/docs/products/multigov/guides/deploy-to-evm/) +## Perform a CCTP Transfer -- :octicons-rocket-16:{ .lg .middle } **Deploy to Solana** +This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. - --- +Start by defining utility functions for signer and token setup: - Set up and deploy the MultiGov Staking Program on Solana with step-by-step instructions for configuring, funding, deploying, and initializing the program. +1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: - [:custom-arrow: Discover how to deploy MultiGov on Solana](/docs/products/multigov/guides/deploy-to-solana/) + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on EVM Chains** +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; - --- + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } - Learn the process and key considerations for upgrading MultiGov contracts, ensuring system integrity and careful planning across cross-chain components. + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` - [:custom-arrow: Discover how to upgrade MultiGov on EVM Chains](/docs/products/multigov/guides/upgrade-evm/) +2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: -- :octicons-file-code-16:{ .lg .middle } **Upgrade MultiGov on Solana** + ```ts title="transfer.ts" + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helper'; - --- +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) + const wh = await wormhole('Testnet', [evm, solana, sui]); - Learn how to upgrade the MultiGov Staking Program on Solana, including updating the program binary, IDL, and more. + // Grab chain Contexts -- these hold a reference to a cached rpc client + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); - [:custom-arrow: Discover how to upgrade MultiGov on Solana](/docs/products/multigov/guides/upgrade-solana/) + // Get signer from local key + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -- :octicons-question-16:{ .lg .middle } **Technical FAQs** + // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; - --- + const automatic = false; - Find answers to common technical questions about MultiGov, covering technical setup, security, proposal creation, and more. + // Create the circleTransfer transaction (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); - [:custom-arrow: Find the answer to your technical questions](/docs/products/multigov/faqs/) + const quote = await CircleTransfer.quoteTransfer( + sendChain, + rcvChain, + xfer.transfer + ); + console.log('Quote: ', quote); -
    + // Step 1: Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); -## Additional Resources + // Step 2: Wait for Circle Attestation (VAA) + const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); -
    + // Step 3: Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); -- :octicons-book-16:{ .lg .middle } **What is MultiGov?** + process.exit(0); +})(); + ``` - --- +3. Run the script to execute the transfer: - Need to familiarize yourself with MultiGov? Discover everything you need to know about MultiGov, Wormhole's cross-chain governance solution. + ```bash + npx tsx transfer.ts + ``` - [:custom-arrow: Learn the basics](/docs/learn/governance/) + You will see terminal output similar to the following: -- :octicons-checklist-16:{ .lg .middle } **Tutorials** +
    +npx tsx transfer.ts +Starting Transfer +Started Transfer: + [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', + '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] + +Waiting for Attestation +Retrying Circle:GetAttestation, attempt 0/60 +Retrying Circle:GetAttestation, attempt 1/60 + +Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] + +Completing Transfer +Completed Transfer: + [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] + +
    - --- +To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. - Access step-by-step tutorials for executing cross-chain governance actions, including treasury management proposals with MultiGov. +## Next Steps - [:custom-arrow: Learn by building](/docs/tutorials/multigov/) +Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: -
    + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/queries/overview/ +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/cctp-contracts/ --- BEGIN CONTENT --- --- -title: Queries Overview -description: Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -categories: Queries +title: Interacting with CCTP Contracts +description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. +categories: Transfer --- -# Queries Overview {: #queries-overview } - -Wormhole Guardians, who run full nodes for various connected chains, facilitate a new cross-chain query service that allows for on-demand attested responses to queries, bypassing the inefficiencies of traditional transaction-based data retrieval. This method is faster and cost-effective, eliminating the need for gas payments and transaction finality wait times. - -!!! note - Queries are currently in closed beta, though you can start developing today. Check out [Use Queries](/docs/build/queries/use-queries/){target=\_blank} and reach out to [Join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. - -Wormhole Queries offers on-demand access to Guardian-attested on-chain data. The current implementation provides integrators with a simple REST endpoint to initiate an off-chain request via a proxy. The proxy then forwards the request to the Guardians and gathers a quorum of responses. The result returns the encoded response, including the request details and the Guardian signatures. The request validation performed by the query module includes a three step process that involves verifying the signature to ensure it has the correct prefix, confirming that the signer is authorized to execute query requests, and validating the legitimacy of all per-chain requests contained in the query. You can read more about Queries in the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank}. +# Interact with CCTP Contracts -## The Flow of a Query {: #the-flow-of-a-query} - -The general overview of a query's flow is as follows: an off-chain process sends HTTPS query requests to a Query Proxy, which validates and forwards them to the Guardians; these Guardians independently validate, sign, and return the response, with the entire process typically taking less than a second. +## Introduction -![The architecture flow of a query](/docs/images/build/queries/overview/overview-1.webp) +Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/products/cctp-bridge/overview/){target=\_blank} is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. -The step-by-step flow of a query is as follows: +As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. -1. An off-chain process initiates a query request via HTTPS to the query proxy (or Query Server) -2. The query proxy validates the request and forwards it to the Guardians via a gossip network -3. The Guardians independently validate the request, make the requisite RPC calls, verify the results, sign, and gossip a response back to the Query Proxy -4. The Query Proxy aggregates the results and returns a response when it reaches a quorum of two-thirds or more of the current Guardian set - the exact quorum requirements as the core bridge -5. The off-chain process can then submit these requests to an on-chain contract which should verify the signatures and validate the request before processing the result +This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. -In this flow, the Query Proxy is a permissioned but trustless part of the protocol. In most cases, this entire process takes less than one second. If a request is invalid or cannot be processed by the Guardians, they will retry for up to one minute before timing out. Requests can be batched to have the Guardians make multiple calls to multiple networks. This can further reduce overhead for processing query responses on-chain. Up to 255 queries can be batched together, with certain types allowing for batching themselves. +## Prerequisites -## Supported Query Types {: #supported-query-types} +To interact with the Wormhole CCTP, you'll need the following: -There are currently five supported types of queries. See [the white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md){target=\_blank} for more details on each. +- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -### eth_call {: #eth-call} +## Wormhole's CCTP Integration Contract -This query type is effectively an equivalent of [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a block specified by number or hash. +Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). -Calls are batched to allow specifying multiple calls (even to multiple contracts) against the same block. These calls are included in a single batch RPC call, simplifying on-chain verification. Up to 255 calls may be batched in an single `eth_call` query. +The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. -The result contains the specified block number, hash, timestamp, and the call result. +This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. -### eth_call By Timestamp {: #eth-call-by-timestamp} +!!! note + Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. -This query type is similar to `eth_call` but targets a timestamp instead of a specific `block_id`. This can be useful when forming requests based on uncorrelated data, such as requiring data from another chain based on the block timestamp of a given chain. +??? code "Circle Integration contract" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; -The result also contains the target and block details with the following enforced conditions: `target_block.timestamp <= target_time < following_block.timestamp` and `following_block_num - 1 == target_block_num`. +import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IWormhole} from "wormhole/interfaces/IWormhole.sol"; +import {BytesLib} from "wormhole/libraries/external/BytesLib.sol"; -### eth_call With Finality {: #eth-call-with-finality} +import {ICircleBridge} from "../interfaces/circle/ICircleBridge.sol"; -This query type is similar to `eth_call` but ensures that the specified block has reached the specified finality before returning the query results. The finality may be `finalized` or `safe.` Note that if a chain doesn't natively support the `safe` tag, this will be equivalent to `finalized.` +import {CircleIntegrationGovernance} from "./CircleIntegrationGovernance.sol"; +import {CircleIntegrationMessages} from "./CircleIntegrationMessages.sol"; -### sol_account {: #sol_account} - -This query is used to read data for one or more accounts on Solana, akin to [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank}. - -### sol_pda {: #sol_pda} - -This query is used to read data for one or more [Program Derived Addresses(PDA)](https://www.anchor-lang.com/docs/pdas){target=\_blank} on Solana, akin to calling [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} on the result of `PublicKey.findProgramAddressSync(seeds, programId).` This query is helpful for times when you want to more generally read accounts owned by a program and verify the derivation on another chain, like how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. +/** + * @notice This contract burns and mints Circle-supported tokens by using Circle's Cross-Chain Transfer Protocol. It also emits + * Wormhole messages with arbitrary payloads to allow for additional composability when performing cross-chain + * transfers of Circle-suppored assets. + */ +contract CircleIntegration is + CircleIntegrationMessages, + CircleIntegrationGovernance, + ReentrancyGuard +{ + using BytesLib for bytes; -## Supported Chains {: #supported-chains} + /** + * @notice Emitted when Circle-supported assets have been minted to the mintRecipient + * @param emitterChainId Wormhole chain ID of emitter contract on source chain + * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on source chain + * @param sequence Sequence of Wormhole message used to mint tokens + */ + event Redeemed( + uint16 indexed emitterChainId, + bytes32 indexed emitterAddress, + uint64 indexed sequence + ); -The following table provides expected support based on testing. However, the success of any given query is based on the success of the underlying call on each Guardian’s RPC node. + /** + * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits + * a Wormhole message containing a user-specified payload with instructions for what to do with + * the Circle-supported assets once they have been minted on the target chain. + * @dev reverts if: + * - user passes insufficient value to pay Wormhole message fee + * - `token` is not supported by Circle Bridge + * - `amount` is zero + * - `targetChain` is not supported + * - `mintRecipient` is bytes32(0) + * @param transferParams Struct containing the following attributes: + * - `token` Address of the token to be burned + * - `amount` Amount of `token` to be burned + * - `targetChain` Wormhole chain ID of the target blockchain + * - `mintRecipient` The recipient wallet or contract address on the target chain + * @param batchId ID for Wormhole message batching + * @param payload Arbitrary payload to be delivered to the target chain via Wormhole + * @return messageSequence Wormhole sequence number for this contract + */ + function transferTokensWithPayload( + TransferParameters memory transferParams, + uint32 batchId, + bytes memory payload + ) public payable nonReentrant returns (uint64 messageSequence) { + // cache wormhole instance and fees to save on gas + IWormhole wormhole = wormhole(); + uint256 wormholeFee = wormhole.messageFee(); -For example, many chains have implementations forked from [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which keeps 128 blocks of state in memory by default (without running in archive mode). While this is good for about 25 minutes of history on Ethereum Mainnet, it is only about three minutes on Optimism. While Guardian nodes can be expected to have access to recent state, there are currently no guarantees of how far back in history they have access to. + // confirm that the caller has sent enough ether to pay for the wormhole message fee + require(msg.value == wormholeFee, "insufficient value"); -### Mainnet {: #mainnet} + // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` + // should be the target contract (or wallet) composing on this contract. + (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}( + transferParams.token, + transferParams.amount, + transferParams.targetChain, + transferParams.mintRecipient + ); -| Chain | Wormhole Chain ID | eth_call | By Timestamp | With Finality | Expected History | -|:-------------:|:-----------------:|:--------:|:------------------:|:-------------:|:----------------:| -| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | -| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | -| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | -| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | -| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | -| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | -| Karura | 11 | ✅ | ✅ | ✅ | archive | -| Acala | 12 | ✅ | ✅ | ✅ | archive | -| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | -| Celo | 14 | ✅ | ℹ️ hints required\* | ✅ | 128 blocks | -| Moonbeam | 16 | ✅ | ℹ️ hints required\* | ✅ | 256 blocks | -| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | -| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | -| Base | 30 | ✅ | ✅ | ✅ | archive | + // encode DepositWithPayload message + bytes memory encodedMessage = encodeDepositWithPayload( + DepositWithPayload({ + token: addressToBytes32(transferParams.token), + amount: amountReceived, + sourceDomain: localDomain(), + targetDomain: getDomainFromChainId(transferParams.targetChain), + nonce: nonce, + fromAddress: addressToBytes32(msg.sender), + mintRecipient: transferParams.mintRecipient, + payload: payload + }) + ); -\*`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. + // send the DepositWithPayload wormhole message + messageSequence = wormhole.publishMessage{value: wormholeFee}( + batchId, + encodedMessage, + wormholeFinality() + ); + } -## Next Steps {: #next-steps} + function _transferTokens( + address token, + uint256 amount, + uint16 targetChain, + bytes32 mintRecipient + ) internal returns (uint64 nonce, uint256 amountReceived) { + // sanity check user input + require(amount > 0, "amount must be > 0"); + require(mintRecipient != bytes32(0), "invalid mint recipient"); + require(isAcceptedToken(token), "token not accepted"); + require( + getRegisteredEmitter(targetChain) != bytes32(0), + "target contract not registered" + ); -Remember that Wormhole Queries are currently in beta. You can [register to join the beta](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to fully experiment with Wormhole Queries. + // take custody of tokens + amountReceived = custodyTokens(token, amount); -Be sure to check out the [FAQs](/docs/products/queries/faqs/){target=\_blank} and the [Use Queries guide](/docs/build/queries/use-queries/){target=\_blank}. + // cache Circle Bridge instance + ICircleBridge circleBridge = circleBridge(); -You can also check out the following examples of applications that make use of Wormhole Queries: + // approve the Circle Bridge to spend tokens + SafeERC20.safeApprove( + IERC20(token), + address(circleBridge), + amountReceived + ); -- [Basic demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} ---- END CONTENT --- + // burn tokens on the bridge + nonce = circleBridge.depositForBurnWithCaller( + amountReceived, + getDomainFromChainId(targetChain), + mintRecipient, + token, + getRegisteredEmitter(targetChain) + ); + } -Doc-Content: https://wormhole.com/docs/..build/queries/use-queries/ ---- BEGIN CONTENT --- ---- -title: Use Queries -description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -categories: Queries ---- + function custodyTokens( + address token, + uint256 amount + ) internal returns (uint256) { + // query own token balance before transfer + (, bytes memory queriedBalanceBefore) = token.staticcall( + abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) + ); + uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); -# Use Queries + // deposit tokens + SafeERC20.safeTransferFrom( + IERC20(token), + msg.sender, + address(this), + amount + ); -You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. + // query own token balance after transfer + (, bytes memory queriedBalanceAfter) = token.staticcall( + abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) + ); + uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); -This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. + return balanceAfter - balanceBefore; + } -## RPC Basics + /** + * @notice `redeemTokensWithPayload` verifies the Wormhole message from the source chain and + * verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge + * contract by passing the Circle message and attestation to mint tokens to the specified + * mint recipient. It also verifies that the caller is the specified mint recipient to ensure + * atomic execution of the additional instructions in the Wormhole message. + * @dev reverts if: + * - Wormhole message is not properly attested + * - Wormhole message was not emitted from a registered contrat + * - Wormhole message was already consumed by this contract + * - msg.sender is not the encoded mintRecipient + * - Circle Bridge message and Wormhole message are not associated + * - `receiveMessage` call to Circle Transmitter fails + * @param params Struct containing the following attributes: + * - `encodedWormholeMessage` Wormhole message emitted by a registered contract including + * information regarding the token burn on the source chain and an arbitrary message. + * - `circleBridgeMessage` Message emitted by Circle Bridge contract with information regarding + * the token burn on the source chain. + * - `circleAttestation` Serialized EC Signature attesting the cross-chain transfer + * @return depositInfo Struct containing the following attributes: + * - `token` Address (bytes32 left-zero-padded) of token to be minted + * - `amount` Amount of tokens to be minted + * - `sourceDomain` Circle domain for the source chain + * - `targetDomain` Circle domain for the target chain + * - `nonce` Circle sequence number for the transfer + * - `fromAddress` Source CircleIntegration contract caller's address + * - `mintRecipient` Recipient of minted tokens (must be caller of this contract) + * - `payload` Arbitrary Wormhole message payload + */ + function redeemTokensWithPayload( + RedeemParameters calldata params + ) public returns (DepositWithPayload memory depositInfo) { + // verify the wormhole message + IWormhole.VM memory verifiedMessage = verifyWormholeRedeemMessage( + params.encodedWormholeMessage + ); -Before digging into anything Queries-specific, this page will look at how to make an [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} against a public Ethereum RPC. Suppose you'd like to query the WETH contract for its total supply; before making a request, you need some information about the contract you want to call, including: + // Decode the message payload into the DepositWithPayload struct. Call the Circle TokenMinter + // contract to determine the address of the encoded token on this chain. + depositInfo = decodeDepositWithPayload(verifiedMessage.payload); + depositInfo.token = fetchLocalTokenAddress( + depositInfo.sourceDomain, + depositInfo.token + ); -- **To** - the contract to call. WETH is [0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2){target=\_blank} -- **Data** - the method identifier and ABI-encoded parameters, which can be obtained as follows: `web3.eth.abi.encodeFunctionSignature("totalSupply()")` which yields `0x18160ddd` -- **Block ID** - the block number, hash, or tag. Tag options include `latest,` `safe,` or `finalized` + // confirm that circle gave us a valid token address + require(depositInfo.token != bytes32(0), "invalid local token address"); -The prepared curl request is as follows: + // confirm that the caller is the `mintRecipient` to ensure atomic execution + require( + addressToBytes32(msg.sender) == depositInfo.mintRecipient, + "caller must be mintRecipient" + ); -```bash title="eth_call JSON-RPC request" -curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' -``` + // confirm that the caller passed the correct message pair + require( + verifyCircleMessage( + params.circleBridgeMessage, + depositInfo.sourceDomain, + depositInfo.targetDomain, + depositInfo.nonce + ), + "invalid message pair" + ); -And the corresponding response is: + // call the circle bridge to mint tokens to the recipient + bool success = circleTransmitter().receiveMessage( + params.circleBridgeMessage, + params.circleAttestation + ); + require(success, "CIRCLE_INTEGRATION: failed to mint tokens"); -```bash title="eth_call JSON-RPC reponse" -{ - "jsonrpc":"2.0", - "id":1, - "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" -} -``` + // emit Redeemed event + emit Redeemed( + verifiedMessage.emitterChainId, + verifiedMessage.emitterAddress, + verifiedMessage.sequence + ); + } -Converting the returned value of the executed call from hexidecimal results in the value `3172615244782286193073777`. You can compare your result to the [**Read Contract**](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#readContract){target=\_blank} tab in Etherscan. Your result will be different as WETH is minted/burned over time. + function verifyWormholeRedeemMessage( + bytes memory encodedMessage + ) internal returns (IWormhole.VM memory) { + require(evmChain() == block.chainid, "invalid evm chain"); -## Construct a Query {: #construct-a-query} + // parse and verify the Wormhole core message + ( + IWormhole.VM memory verifiedMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. + // confirm that the core layer verified the message + require(valid, reason); -```jsx -npm i @wormhole-foundation/wormhole-query-sdk axios -``` + // verify that this message was emitted by a trusted contract + require(verifyEmitter(verifiedMessage), "unknown emitter"); -In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. + // revert if this message has been consumed already + require( + !isMessageConsumed(verifiedMessage.hash), + "message already consumed" + ); + consumeMessage(verifiedMessage.hash); -You can request the latest block from a public node using `eth_getBlockByNumber`. + return verifiedMessage; + } -```jsx + function verifyEmitter( + IWormhole.VM memory vm + ) internal view returns (bool) { + // verify that the sender of the wormhole message is a trusted + return (getRegisteredEmitter(vm.emitterChainId) == vm.emitterAddress && + vm.emitterAddress != bytes32(0)); + } -await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; -``` - -Then construct the call data. - -```jsx -to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; -``` - -Finally, put it all together in a `QueryRequest`. + function verifyCircleMessage( + bytes memory circleMessage, + uint32 sourceDomain, + uint32 targetDomain, + uint64 nonce + ) internal pure returns (bool) { + // parse the circle bridge message inline + uint32 circleSourceDomain = circleMessage.toUint32(4); + uint32 circleTargetDomain = circleMessage.toUint32(8); + uint64 circleNonce = circleMessage.toUint64(12); -```jsx -const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); -``` + // confirm that both the Wormhole message and Circle message share the same transfer info + return (sourceDomain == circleSourceDomain && + targetDomain == circleTargetDomain && + nonce == circleNonce); + } -This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. + /** + * @notice Fetches the local token address given an address and domain from + * a different chain. + * @param sourceDomain Circle domain for the sending chain. + * @param sourceToken Address of the token for the sending chain. + * @return Address bytes32 formatted address of the `sourceToken` on this chain. + */ + function fetchLocalTokenAddress( + uint32 sourceDomain, + bytes32 sourceToken + ) public view returns (bytes32) { + return + addressToBytes32( + circleTokenMinter().remoteTokensToLocalTokens( + keccak256(abi.encodePacked(sourceDomain, sourceToken)) + ) + ); + } -```jsx + /** + * @notice Converts type address to bytes32 (left-zero-padded) + * @param address_ Address to convert to bytes32 + * @return Address bytes32 + */ + function addressToBytes32(address address_) public pure returns (bytes32) { + return bytes32(uint256(uint160(address_))); + } +} + ``` -// { -// "nonce": 0, -// "requests": [ -// { -// "chainId": 2, -// "query": { -// "callData": [ -// { -// "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", -// "data": "0x18160ddd" -// } -// ], -// "blockTag": "0x11e9068" -// } -// } -// ], -// "version": 1 -// } -``` +The functions provided by the Circle Integration contract are as follows: -## Mock a Query +- **`transferTokensWithPayload`** - calls the Circle Bridge contract to burn Circle-supported tokens. It emits a Wormhole message containing a user-specified payload with instructions for what to do with the Circle-supported assets once they have been minted on the target chain -For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. + ??? interface "Parameters" -```jsx -const mockData = await mock.mock(request); - console.log(mockData); -// { -// signatures: ['...'], -// bytes: '...' -// } -``` + `transferParams` ++"TransferParameters"++ -This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. + A tuple containing the parameters for the transfer. -```jsx -const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -// Mock Query Result: 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee (3172556167631284394053614) -``` + ??? child "`TransferParameters` struct" -Testing this all together might look like the following: + `token` ++"address"++ -```jsx -import { - EthCallData, - EthCallQueryRequest, - EthCallQueryResponse, - PerChainQueryRequest, - QueryProxyMock, - QueryRequest, - QueryResponse, -} from '@wormhole-foundation/wormhole-query-sdk'; -import axios from 'axios'; + Address of the token to be burned. -const rpc = 'https://ethereum.publicnode.com'; -const callData: EthCallData = { - to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH - data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") -}; + --- -(async () => { - const latestBlock: string = ( - await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; - if (!latestBlock) { - console.error(`❌ Invalid block returned`); - return; - } - console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); - const targetResponse = await axios.post(rpc, { - method: 'eth_call', - params: [callData, latestBlock], - id: 1, - jsonrpc: '2.0', - }); - // console.log(finalizedResponse.data); - if (targetResponse.data.error) { - console.error(`❌ ${targetResponse.data.error.message}`); - } - const targetResult = targetResponse.data?.result; - console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); - // Form the query request - const request = new QueryRequest( - 0, // Nonce - [ - new PerChainQueryRequest( - 2, // Ethereum Wormhole Chain ID - new EthCallQueryRequest(latestBlock, [callData]) - ), - ] - ); - console.log(JSON.stringify(request, undefined, 2)); - const mock = new QueryProxyMock({ 2: rpc }); - const mockData = await mock.mock(request); - console.log(mockData); - const mockQueryResponse = QueryResponse.from(mockData.bytes); - const mockQueryResult = ( - mockQueryResponse.responses[0].response as EthCallQueryResponse - ).results[0]; - console.log( - `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` - ); -})(); -``` + `amount` ++"uint256"++ -### Fork Testing + Amount of the token to be burned. -It is common to test against a local fork of Mainnet with something like + --- -```jsx -anvil --fork-url https://ethereum.publicnode.com -``` + `targetChain` ++"uint16"++ -In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. + Wormhole chain ID of the target blockchain. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. + --- -```jsx -npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe -``` + `mintRecipient` ++"bytes32"++ -If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. + The recipient wallet or contract address on the target chain. -## Make a Query Request + --- -The standardized means of making a `QueryRequest` with an API key is as follows: + `batchId` ++"uint32"++ -```jsx -const serialized = request.serialize(); -const proxyResponse = (await axios.post)( - QUERY_URL, - { - bytes: Buffer.from(serialized).toString('hex'), - }, - { headers: { 'X-API-Key': YOUR_API_KEY } } -); - -``` + The ID for Wormhole message batching. -Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. + --- -A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` + `payload` ++"bytes"++ -A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` + Arbitrary payload to be delivered to the target chain via Wormhole. -## Verify a Query Response On-Chain + ??? interface "Returns" -A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: + `messageSequence` ++"uint64"++ -```bash -forge install wormhole-foundation/wormhole-solidity-sdk -``` + Wormhole sequence number for this contract. -Broadly, using a query response on-chain comes down to three main steps: +- `redeemTokensWithPayload` - verifies the Wormhole message from the source chain and verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge contract by passing the Circle message and attestation to the `receiveMessage` function, which is responsible for minting tokens to the specified mint recipient. It also verifies that the caller is the specified mint recipient to ensure atomic execution of the additional instructions in the Wormhole message - 1. Parse and verify the query response - 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract - 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: - - Is the request against the expected chain? - - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing - - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks - - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases - - Is the result of the expected length for the expected result type? - 4. Run `abi.decode` on the result + ??? interface "Parameters" -See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. + `params` ++"RedeemParameters"++ -??? code "View the complete `QueryDemo`" - ```solidity - // contracts/query/QueryDemo.sol -// SPDX-License-Identifier: Apache 2 + A tuple containing the parameters for the redemption. -pragma solidity ^0.8.0; - -import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; -import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "wormhole-solidity-sdk/QueryResponse.sol"; - -error InvalidOwner(); -// @dev for the onlyOwner modifier -error InvalidCaller(); -error InvalidCalldata(); -error InvalidForeignChainID(); -error ObsoleteUpdate(); -error StaleUpdate(); -error UnexpectedResultLength(); -error UnexpectedResultMismatch(); - -/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. -contract QueryDemo is QueryResponse { - using BytesParsing for bytes; - - struct ChainEntry { - uint16 chainID; - address contractAddress; - uint256 counter; - uint256 blockNum; - uint256 blockTime; - } + ??? child "`RedeemParameters` struct" - address private immutable owner; - uint16 private immutable myChainID; - mapping(uint16 => ChainEntry) private counters; - uint16[] private foreignChainIDs; + `encodedWormholeMessage` ++"bytes"++ - bytes4 public GetMyCounter = bytes4(hex"916d5743"); + Wormhole message emitted by a registered contract including information regarding the token burn on the source chain and an arbitrary message. - constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { - if (_owner == address(0)) { - revert InvalidOwner(); - } - owner = _owner; + --- - myChainID = _myChainID; - counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); - } + `circleBridgeMessage` ++"bytes"++ - // updateRegistration should be used to add the other chains and to set / update contract addresses. - function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { - if (counters[_chainID].chainID == 0) { - foreignChainIDs.push(_chainID); - counters[_chainID].chainID = _chainID; - } + Message emitted by Circle Bridge contract with information regarding the token burn on the source chain. - counters[_chainID].contractAddress = _contractAddress; - } + --- - // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. - function getMyCounter() public view returns (uint256) { - return counters[myChainID].counter; - } + `circleAttestation` ++"bytes"++ - // getState() returns this chain's view of all the counters. It is meant to be used in the front end. - function getState() public view returns (ChainEntry[] memory) { - ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); - ret[0] = counters[myChainID]; - uint256 length = foreignChainIDs.length; + Serialized EC signature attesting the cross-chain transfer. - for (uint256 i = 0; i < length;) { - ret[i + 1] = counters[foreignChainIDs[i]]; - unchecked { - ++i; - } - } + ??? interface "Returns" - return ret; - } + `depositInfo` ++"DepositWithPayload"++ - // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. - function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { - ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); - uint256 numResponses = r.responses.length; - if (numResponses != foreignChainIDs.length) { - revert UnexpectedResultLength(); - } + Information about the deposit. - for (uint256 i = 0; i < numResponses;) { - // Create a storage pointer for frequently read and updated data stored on the blockchain - ChainEntry storage chainEntry = counters[r.responses[i].chainId]; - if (chainEntry.chainID != foreignChainIDs[i]) { - revert InvalidForeignChainID(); - } + ??? child "`DepositWithPayload` struct" - EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); + `token` ++"bytes32"++ - // Validate that update is not obsolete - validateBlockNum(eqr.blockNum, chainEntry.blockNum); + Address (`bytes32` left-zero-padded) of token to be minted. - // Validate that update is not stale - validateBlockTime(eqr.blockTime, block.timestamp - 300); + --- - if (eqr.result.length != 1) { - revert UnexpectedResultMismatch(); - } + `amount` ++"uint256"++ - // Validate addresses and function signatures - address[] memory validAddresses = new address[](1); - bytes4[] memory validFunctionSignatures = new bytes4[](1); - validAddresses[0] = chainEntry.contractAddress; - validFunctionSignatures[0] = GetMyCounter; + Amount of tokens to be minted. + + --- - validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); + `sourceDomain` ++"uint32"++ - require(eqr.result[0].result.length == 32, "result is not a uint256"); + Circle domain for the source chain. - chainEntry.blockNum = eqr.blockNum; - chainEntry.blockTime = eqr.blockTime / 1_000_000; - chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); + --- - unchecked { - ++i; - } - } + `targetDomain` ++"uint32"++ - counters[myChainID].blockNum = block.number; - counters[myChainID].blockTime = block.timestamp; - counters[myChainID].counter += 1; - } + Circle domain for the target chain. - modifier onlyOwner() { - if (owner != msg.sender) { - revert InvalidOwner(); - } - _; - } -} - ``` + --- -## Submit a Query Response On-Chain + `nonce` ++"uint64"++ -The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. + Circle sequence number for the transfer. -This example submits the transaction to the demo contract: + --- -```jsx -const tx = await contract.updateCounters( - `0x${response.data.bytes}`, - signaturesToEvmStruct(response.data.signatures) -); -``` ---- END CONTENT --- + `fromAddress` ++"bytes32"++ -Doc-Content: https://wormhole.com/docs/..build/start-building/use-cases/ ---- BEGIN CONTENT --- ---- -title: Use Cases -description: Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -categories: Basics ---- + Source Circle Integration contract caller's address. -# Wormhole Use Cases + --- -
    -
    + `mintRecipient` ++"bytes32"++ -## Cross-Chain Swaps and Liquidity Aggregation + Recipient of minted tokens (must be caller of this contract). -Enable seamless swaps between chains with real-time liquidity routing. + --- -
    -
    + `payload` ++"bytes"++ -🛠 **Wormhole products used:** + Arbitrary Wormhole message payload. -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – handles user-friendly asset transfers -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native assets across chains -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time prices for optimal trade execution + ??? interface "Emits" -🔗 **Used in:** Decentralized exchanges (DEXs) and liquidity aggregators
    🏗️ **Used by:** [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank} + `Redeemed` - event emitted when Circle-supported assets have been minted to the `mintRecipient` -
    -
    + ??? child "Event arguments" + `emitterChainId` ++"uint16"++ -
    -
    + Wormhole chain ID of emitter contract on source chain. -## Borrowing and Lending Across Chains + --- -Let users borrow assets on one chain using collateral from another. + `emitterAddress` ++"bytes32"++ -
    -
    + Address (`bytes32` zero-left-padded) of emitter on source chain. -🛠 **Wormhole products used:** + --- -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves loan requests and liquidations across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers collateral as native assets -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches interest rates and asset prices in real-time + `sequence` ++"uint64"++ -🔗 **Used in:** Lending protocols and yield platforms
    🏗️ **Used by:** [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank} + Sequence of Wormhole message used to mint tokens. -
    -
    +## Circle's CCTP Contracts +Three key contracts power Circle's CCTP: -
    -
    +- **`TokenMessenger`** - the entry point for cross-chain USDC transfers, routing messages to initiate USDC burns on the source chain, and mint USDC on the destination chain +- **`MessageTransmitter`** - handles generic message passing, sending messages from the source chain and receiving them on the destination chain +- **`TokenMinter`** - responsible for the actual minting and burning of USDC, utilizing chain-specific settings for both the burners and minters across different networks -## Real-Time Price Feeds and Trading Strategies +The following sections will examine these contracts in-depth, focusing on the methods invoked indirectly through function calls in the Wormhole Circle Integration contract. -Fetch price feeds across multiple chains for DeFi applications. +!!! note + When using Wormhole's CCTP integration, you will not directly interact with these contracts. You will indirectly interact with them through the Wormhole Circle Integration contract. -
    -
    +These contracts can be found in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/){target=\_blank} on GitHub. -🛠 **Wormhole products used:** +### Token Messenger Contract -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches price feeds from oracles and trading platforms -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – sends signals to execute trades +The Token Messenger contract enables cross-chain USDC transfers by coordinating message exchanges between blockchains. It works alongside the Message Transmitter contract to relay messages for burning USDC on a source chain and minting it on a destination chain. The contract emits events to track both the burning of tokens and their subsequent minting on the destination chain. -🔗 **Used in:** Trading bots, arbitrage platforms, and oracles
    🏗️ **Used by:** [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank} +To ensure secure communication, the Token Messenger restricts message handling to registered remote Token Messenger contracts only. It verifies the proper conditions for token burning and manages local and remote minters using chain-specific settings. -
    -
    +Additionally, the contract provides methods for updating or replacing previously sent burn messages, adding or removing remote Token Messenger contracts, and managing the minting process for cross-chain transfers. +??? code "Token Messenger contract" + ```solidity + /* + * Copyright (c) 2022, Circle Internet Financial Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +pragma solidity 0.7.6; -
    -
    +import "./interfaces/IMessageHandler.sol"; +import "./interfaces/ITokenMinter.sol"; +import "./interfaces/IMintBurnToken.sol"; +import "./interfaces/IMessageTransmitter.sol"; +import "./messages/BurnMessage.sol"; +import "./messages/Message.sol"; +import "./roles/Rescuable.sol"; -## Asset Movement Between Bitcoin and Other Chains +/** + * @title TokenMessenger + * @notice Sends messages and receives messages to/from MessageTransmitters + * and to/from TokenMinters + */ +contract TokenMessenger is IMessageHandler, Rescuable { + // ============ Events ============ + /** + * @notice Emitted when a DepositForBurn message is sent + * @param nonce unique nonce reserved by message + * @param burnToken address of token burnt on source domain + * @param amount deposit amount + * @param depositor address where deposit is transferred from + * @param mintRecipient address receiving minted tokens on destination domain as bytes32 + * @param destinationDomain destination domain + * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32 + * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). + * If equal to bytes32(0), any address can call receiveMessage(). + */ + event DepositForBurn( + uint64 indexed nonce, + address indexed burnToken, + uint256 amount, + address indexed depositor, + bytes32 mintRecipient, + uint32 destinationDomain, + bytes32 destinationTokenMessenger, + bytes32 destinationCaller + ); -Enable direct BTC transfers without wrapped assets. + /** + * @notice Emitted when tokens are minted + * @param mintRecipient recipient address of minted tokens + * @param amount amount of minted tokens + * @param mintToken contract address of minted token + */ + event MintAndWithdraw( + address indexed mintRecipient, + uint256 amount, + address indexed mintToken + ); -
    -
    + /** + * @notice Emitted when a remote TokenMessenger is added + * @param domain remote domain + * @param tokenMessenger TokenMessenger on remote domain + */ + event RemoteTokenMessengerAdded(uint32 domain, bytes32 tokenMessenger); -🛠 **Wormhole products used:** + /** + * @notice Emitted when a remote TokenMessenger is removed + * @param domain remote domain + * @param tokenMessenger TokenMessenger on remote domain + */ + event RemoteTokenMessengerRemoved(uint32 domain, bytes32 tokenMessenger); -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers BTC across chains + /** + * @notice Emitted when the local minter is added + * @param localMinter address of local minter + * @notice Emitted when the local minter is added + */ + event LocalMinterAdded(address localMinter); -🔗 **Used in:** Bitcoin DeFi and lightning network integrations
    🏗️ **Used by:** [Synonym](https://wormhole.com/case-studies/synonym){target=\_blank} + /** + * @notice Emitted when the local minter is removed + * @param localMinter address of local minter + * @notice Emitted when the local minter is removed + */ + event LocalMinterRemoved(address localMinter); -
    -
    + // ============ Libraries ============ + using TypedMemView for bytes; + using TypedMemView for bytes29; + using BurnMessage for bytes29; + using Message for bytes29; -
    -
    + // ============ State Variables ============ + // Local Message Transmitter responsible for sending and receiving messages to/from remote domains + IMessageTransmitter public immutable localMessageTransmitter; -## Decentralized Social Platforms + // Version of message body format + uint32 public immutable messageBodyVersion; -Enable seamless communication and asset transfer across decentralized social networks. + // Minter responsible for minting and burning tokens on the local domain + ITokenMinter public localMinter; -
    -
    + // Valid TokenMessengers on remote domains + mapping(uint32 => bytes32) public remoteTokenMessengers; -🛠 **Wormhole products used:** + // ============ Modifiers ============ + /** + * @notice Only accept messages from a registered TokenMessenger contract on given remote domain + * @param domain The remote domain + * @param tokenMessenger The address of the TokenMessenger contract for the given remote domain + */ + modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) { + require( + _isRemoteTokenMessenger(domain, tokenMessenger), + "Remote TokenMessenger unsupported" + ); + _; + } -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates decentralized interactions -- [**Token Bridge**](/docs/build/transfers/token-bridge/){target=\_blank} – enables cross-chain tokenized rewards + /** + * @notice Only accept messages from the registered message transmitter on local domain + */ + modifier onlyLocalMessageTransmitter() { + // Caller must be the registered message transmitter for this domain + require(_isLocalMessageTransmitter(), "Invalid message transmitter"); + _; + } -🔗 **Used in:** Web3 social networks and content monetization
    🏗️ **Used by:** [Chingari](https://chingari.io/){target=\_blank} + // ============ Constructor ============ + /** + * @param _messageTransmitter Message transmitter address + * @param _messageBodyVersion Message body version + */ + constructor(address _messageTransmitter, uint32 _messageBodyVersion) { + require( + _messageTransmitter != address(0), + "MessageTransmitter not set" + ); + localMessageTransmitter = IMessageTransmitter(_messageTransmitter); + messageBodyVersion = _messageBodyVersion; + } -
    -
    + // ============ External Functions ============ + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. + * Emits a `DepositForBurn` event. + * @dev reverts if: + * - given burnToken is not supported + * - given destinationDomain has no TokenMessenger registered + * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance + * to this contract is less than `amount`. + * - burn() reverts. For example, if `amount` is 0. + * - MessageTransmitter returns false or reverts. + * @param amount amount of tokens to burn + * @param destinationDomain destination domain + * @param mintRecipient address of mint recipient on destination domain + * @param burnToken address of contract to burn deposited tokens, on local domain + * @return _nonce unique nonce reserved by message + */ + function depositForBurn( + uint256 amount, + uint32 destinationDomain, + bytes32 mintRecipient, + address burnToken + ) external returns (uint64 _nonce) { + return + _depositForBurn( + amount, + destinationDomain, + mintRecipient, + burnToken, + // (bytes32(0) here indicates that any address can call receiveMessage() + // on the destination domain, triggering mint to specified `mintRecipient`) + bytes32(0) + ); + } + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint + * on the destination domain must be called by `destinationCaller`. + * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible + * to broadcast the message on the destination domain. This is an advanced feature, and the standard + * depositForBurn() should be preferred for use cases where a specific destination caller is not required. + * Emits a `DepositForBurn` event. + * @dev reverts if: + * - given destinationCaller is zero address + * - given burnToken is not supported + * - given destinationDomain has no TokenMessenger registered + * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance + * to this contract is less than `amount`. + * - burn() reverts. For example, if `amount` is 0. + * - MessageTransmitter returns false or reverts. + * @param amount amount of tokens to burn + * @param destinationDomain destination domain + * @param mintRecipient address of mint recipient on destination domain + * @param burnToken address of contract to burn deposited tokens, on local domain + * @param destinationCaller caller on the destination domain, as bytes32 + * @return nonce unique nonce reserved by message + */ + function depositForBurnWithCaller( + uint256 amount, + uint32 destinationDomain, + bytes32 mintRecipient, + address burnToken, + bytes32 destinationCaller + ) external returns (uint64 nonce) { + // Destination caller must be nonzero. To allow any destination caller, use depositForBurn(). + require(destinationCaller != bytes32(0), "Invalid destination caller"); -
    -
    + return + _depositForBurn( + amount, + destinationDomain, + mintRecipient, + burnToken, + destinationCaller + ); + } -## Memecoin Launchpads + /** + * @notice Replace a BurnMessage to change the mint recipient and/or + * destination caller. Allows the sender of a previous BurnMessage + * (created by depositForBurn or depositForBurnWithCaller) + * to send a new BurnMessage to replace the original. + * The new BurnMessage will reuse the amount and burn token of the original, + * without requiring a new deposit. + * @dev The new message will reuse the original message's nonce. For a + * given nonce, all replacement message(s) and the original message are + * valid to broadcast on the destination domain, until the first message + * at the nonce confirms, at which point all others are invalidated. + * Note: The msg.sender of the replaced message must be the same as the + * msg.sender of the original message. + * @param originalMessage original message bytes (to replace) + * @param originalAttestation original attestation bytes + * @param newDestinationCaller the new destination caller, which may be the + * same as the original destination caller, a new destination caller, or an empty + * destination caller (bytes32(0), indicating that any destination caller is valid.) + * @param newMintRecipient the new mint recipient, which may be the same as the + * original mint recipient, or different. + */ + function replaceDepositForBurn( + bytes calldata originalMessage, + bytes calldata originalAttestation, + bytes32 newDestinationCaller, + bytes32 newMintRecipient + ) external { + bytes29 _originalMsg = originalMessage.ref(0); + _originalMsg._validateMessageFormat(); + bytes29 _originalMsgBody = _originalMsg._messageBody(); + _originalMsgBody._validateBurnMessageFormat(); -Launch and distribute memecoins across multiple chains, enabling cross-chain fundraising and liquidity access. + bytes32 _originalMsgSender = _originalMsgBody._getMessageSender(); + // _originalMsgSender must match msg.sender of original message + require( + msg.sender == Message.bytes32ToAddress(_originalMsgSender), + "Invalid sender for message" + ); + require( + newMintRecipient != bytes32(0), + "Mint recipient must be nonzero" + ); -
    -
    + bytes32 _burnToken = _originalMsgBody._getBurnToken(); + uint256 _amount = _originalMsgBody._getAmount(); -🛠 **Wormhole products used:** + bytes memory _newMessageBody = BurnMessage._formatMessage( + messageBodyVersion, + _burnToken, + newMintRecipient, + _amount, + _originalMsgSender + ); -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – enables native asset transfers for seamless fundraising -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – facilitates cross-chain token distribution and claim processes + localMessageTransmitter.replaceMessage( + originalMessage, + originalAttestation, + _newMessageBody, + newDestinationCaller + ); -🔗 **Used in:** Token launchpads, IDOs, and meme token ecosystems - -
    -
    - - -
    -
    - -## Cross-Chain Perpetuals + emit DepositForBurn( + _originalMsg._nonce(), + Message.bytes32ToAddress(_burnToken), + _amount, + msg.sender, + newMintRecipient, + _originalMsg._destinationDomain(), + _originalMsg._recipient(), + newDestinationCaller + ); + } -Enable leveraged perpetual trading across chains with seamless collateral and liquidity management. + /** + * @notice Handles an incoming message received by the local MessageTransmitter, + * and takes the appropriate action. For a burn message, mints the + * associated token to the requested recipient on the local domain. + * @dev Validates the local sender is the local MessageTransmitter, and the + * remote sender is a registered remote TokenMessenger for `remoteDomain`. + * @param remoteDomain The domain where the message originated from. + * @param sender The sender of the message (remote TokenMessenger). + * @param messageBody The message body bytes. + * @return success Bool, true if successful. + */ + function handleReceiveMessage( + uint32 remoteDomain, + bytes32 sender, + bytes calldata messageBody + ) + external + override + onlyLocalMessageTransmitter + onlyRemoteTokenMessenger(remoteDomain, sender) + returns (bool) + { + bytes29 _msg = messageBody.ref(0); + _msg._validateBurnMessageFormat(); + require( + _msg._getVersion() == messageBodyVersion, + "Invalid message body version" + ); -
    -
    + bytes32 _mintRecipient = _msg._getMintRecipient(); + bytes32 _burnToken = _msg._getBurnToken(); + uint256 _amount = _msg._getAmount(); -🛠 **Wormhole products used:** + ITokenMinter _localMinter = _getLocalMinter(); -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time asset prices and manages position state across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - for quick cross-chain token execution, providing efficient and seamless user experiences + _mintAndWithdraw( + address(_localMinter), + remoteDomain, + _burnToken, + Message.bytes32ToAddress(_mintRecipient), + _amount + ); -🔗 **Used in:** Perpetual DEXs, trading platforms and cross-chain derivatives + return true; + } -
    -
    + /** + * @notice Add the TokenMessenger for a remote domain. + * @dev Reverts if there is already a TokenMessenger set for domain. + * @param domain Domain of remote TokenMessenger. + * @param tokenMessenger Address of remote TokenMessenger as bytes32. + */ + function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) + external + onlyOwner + { + require(tokenMessenger != bytes32(0), "bytes32(0) not allowed"); + require( + remoteTokenMessengers[domain] == bytes32(0), + "TokenMessenger already set" + ); -
    -
    + remoteTokenMessengers[domain] = tokenMessenger; + emit RemoteTokenMessengerAdded(domain, tokenMessenger); + } -## Gas Abstraction + /** + * @notice Remove the TokenMessenger for a remote domain. + * @dev Reverts if there is no TokenMessenger set for `domain`. + * @param domain Domain of remote TokenMessenger + */ + function removeRemoteTokenMessenger(uint32 domain) external onlyOwner { + // No TokenMessenger set for given remote domain. + require( + remoteTokenMessengers[domain] != bytes32(0), + "No TokenMessenger set" + ); -Allow users to pay gas fees with any token across different networks, removing friction in multichain interactions. + bytes32 _removedTokenMessenger = remoteTokenMessengers[domain]; + delete remoteTokenMessengers[domain]; + emit RemoteTokenMessengerRemoved(domain, _removedTokenMessenger); + } -
    -
    + /** + * @notice Add minter for the local domain. + * @dev Reverts if a minter is already set for the local domain. + * @param newLocalMinter The address of the minter on the local domain. + */ + function addLocalMinter(address newLocalMinter) external onlyOwner { + require(newLocalMinter != address(0), "Zero address not allowed"); -🛠 **Wormhole products used:** + require( + address(localMinter) == address(0), + "Local minter is already set." + ); -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – routes gas fee payments across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – facilitates native token conversion for gas payments + localMinter = ITokenMinter(newLocalMinter); -🔗 **Used in:** Wallets, dApps, and multichain user experience improvements + emit LocalMinterAdded(newLocalMinter); + } -
    -
    + /** + * @notice Remove the minter for the local domain. + * @dev Reverts if the minter of the local domain is not set. + */ + function removeLocalMinter() external onlyOwner { + address _localMinterAddress = address(localMinter); + require(_localMinterAddress != address(0), "No local minter is set."); + delete localMinter; + emit LocalMinterRemoved(_localMinterAddress); + } -
    -
    + // ============ Internal Utils ============ + /** + * @notice Deposits and burns tokens from sender to be minted on destination domain. + * Emits a `DepositForBurn` event. + * @param _amount amount of tokens to burn (must be non-zero) + * @param _destinationDomain destination domain + * @param _mintRecipient address of mint recipient on destination domain + * @param _burnToken address of contract to burn deposited tokens, on local domain + * @param _destinationCaller caller on the destination domain, as bytes32 + * @return nonce unique nonce reserved by message + */ + function _depositForBurn( + uint256 _amount, + uint32 _destinationDomain, + bytes32 _mintRecipient, + address _burnToken, + bytes32 _destinationCaller + ) internal returns (uint64 nonce) { + require(_amount > 0, "Amount must be nonzero"); + require(_mintRecipient != bytes32(0), "Mint recipient must be nonzero"); -## Bridging Intent Library + bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger( + _destinationDomain + ); -Provide developers with a library of bridging intents and automation functions, enabling plug-and-play interoperability logic. + ITokenMinter _localMinter = _getLocalMinter(); + IMintBurnToken _mintBurnToken = IMintBurnToken(_burnToken); + require( + _mintBurnToken.transferFrom( + msg.sender, + address(_localMinter), + _amount + ), + "Transfer operation failed" + ); + _localMinter.burn(_burnToken, _amount); -
    -
    + // Format message body + bytes memory _burnMessage = BurnMessage._formatMessage( + messageBodyVersion, + Message.addressToBytes32(_burnToken), + _mintRecipient, + _amount, + Message.addressToBytes32(msg.sender) + ); -🛠 **Wormhole products used:** + uint64 _nonceReserved = _sendDepositForBurnMessage( + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller, + _burnMessage + ); -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – enables predefined cross-chain actions and triggers. -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} - provides a framework for executing user-defined bridging intents + emit DepositForBurn( + _nonceReserved, + _burnToken, + _amount, + msg.sender, + _mintRecipient, + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller + ); -🔗 **Used in:** Bridging protocols, DeFi automation, and smart contract libraries + return _nonceReserved; + } -
    -
    + /** + * @notice Sends a BurnMessage through the local message transmitter + * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0), + * or else calls sendMessageWithCaller(). + * @param _destinationDomain destination domain + * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32 + * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0), + * any address can call receiveMessage() on destination domain. + * @param _burnMessage formatted BurnMessage bytes (message body) + * @return nonce unique nonce reserved by message + */ + function _sendDepositForBurnMessage( + uint32 _destinationDomain, + bytes32 _destinationTokenMessenger, + bytes32 _destinationCaller, + bytes memory _burnMessage + ) internal returns (uint64 nonce) { + if (_destinationCaller == bytes32(0)) { + return + localMessageTransmitter.sendMessage( + _destinationDomain, + _destinationTokenMessenger, + _burnMessage + ); + } else { + return + localMessageTransmitter.sendMessageWithCaller( + _destinationDomain, + _destinationTokenMessenger, + _destinationCaller, + _burnMessage + ); + } + } + /** + * @notice Mints tokens to a recipient + * @param _tokenMinter address of TokenMinter contract + * @param _remoteDomain domain where burned tokens originate from + * @param _burnToken address of token burned + * @param _mintRecipient recipient address of minted tokens + * @param _amount amount of minted tokens + */ + function _mintAndWithdraw( + address _tokenMinter, + uint32 _remoteDomain, + bytes32 _burnToken, + address _mintRecipient, + uint256 _amount + ) internal { + ITokenMinter _minter = ITokenMinter(_tokenMinter); + address _mintToken = _minter.mint( + _remoteDomain, + _burnToken, + _mintRecipient, + _amount + ); -
    -
    + emit MintAndWithdraw(_mintRecipient, _amount, _mintToken); + } -## Multichain Prediction Markets + /** + * @notice return the remote TokenMessenger for the given `_domain` if one exists, else revert. + * @param _domain The domain for which to get the remote TokenMessenger + * @return _tokenMessenger The address of the TokenMessenger on `_domain` as bytes32 + */ + function _getRemoteTokenMessenger(uint32 _domain) + internal + view + returns (bytes32) + { + bytes32 _tokenMessenger = remoteTokenMessengers[_domain]; + require(_tokenMessenger != bytes32(0), "No TokenMessenger for domain"); + return _tokenMessenger; + } -Allow users to place bets, manage positions, and receive payouts seamlessly across different networks. + /** + * @notice return the local minter address if it is set, else revert. + * @return local minter as ITokenMinter. + */ + function _getLocalMinter() internal view returns (ITokenMinter) { + require(address(localMinter) != address(0), "Local minter is not set"); + return localMinter; + } -
    -
    + /** + * @notice Return true if the given remote domain and TokenMessenger is registered + * on this TokenMessenger. + * @param _domain The remote domain of the message. + * @param _tokenMessenger The address of the TokenMessenger on remote domain. + * @return true if a remote TokenMessenger is registered for `_domain` and `_tokenMessenger`, + * on this TokenMessenger. + */ + function _isRemoteTokenMessenger(uint32 _domain, bytes32 _tokenMessenger) + internal + view + returns (bool) + { + return + _tokenMessenger != bytes32(0) && + remoteTokenMessengers[_domain] == _tokenMessenger; + } -🛠 **Wormhole products used:** + /** + * @notice Returns true if the message sender is the local registered MessageTransmitter + * @return true if message sender is the registered local message transmitter + */ + function _isLocalMessageTransmitter() internal view returns (bool) { + return + address(localMessageTransmitter) != address(0) && + msg.sender == address(localMessageTransmitter); + } +} + ``` -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches real-time market data, tracks collateral, and manages odds across chains -- [**Wormhole Settlement**](/docs/learn/transfers/settlement/overview/){target=\_blank} – automates token execution for efficient and seamless cross-chain prediction market interactions + This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol){target=\_blank} on GitHub. -🔗 **Used in:** Decentralized betting, prediction markets, and cross-chain gaming +The functions provided by the Token Messenger contract are as follows: -
    -
    +- **`depositForBurn`** - deposits and burns tokens from the sender to be minted on the destination domain. Minted tokens will be transferred to `mintRecipient` + ??? interface "Parameters" -
    -
    + `amount` ++"uint256"++ + + The amount of tokens to burn. -## Cross-Chain Payment Widgets + --- -Allow merchants and platforms to accept payments in any token, auto-converting them into a desired asset. + `destinationDomain` ++"uint32"++ + + The network where the token will be minted after burn. -
    -
    + --- -🛠 **Wormhole products used:** + `mintRecipient` ++"bytes32"++ + + Address of mint recipient on destination domain. -- [**Wormhole Connect**](/docs/products/connect/overview/){target=\_blank} – facilitates seamless payments in various tokens -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – ensures direct, native asset transfers + --- -🔗 **Used in:** E-commerce, Web3 payments, and subscription models + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -
    -
    + ??? interface "Returns" + `_nonce` ++"uint64"++ + + Unique nonce reserved by message. -
    -
    + ??? interface "Emits" -## Oracle Networks + `DepositForBurn` - event emitted when `depositForBurn` is called. The `destinationCaller` is set to `bytes32(0)` to allow any address to call `receiveMessage` on the destination domain -Fetch and verify cross-chain data, enabling reliable, decentralized Oracle services for multichain applications. + ??? child "Event Arguments" -
    -
    + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -🛠 **Wormhole products used:** + --- -- [**Queries**](/docs/build/queries/overview/){target=\_blank} – fetches data from multiple chains and Oracle providers -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – ensures tamper-proof data relay across networks + `burnToken` ++"address"++ + + Address of token burnt on source domain. -🔗 **Used in:** Price feeds, DeFi protocols, and smart contract automation
    🏗️ **Used by:** [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank} + --- -
    -
    + `amount` ++"uint256"++ + + The deposit amount. + --- -
    -
    + `depositor` ++"address"++ + + Address where deposit is transferred from. -## Cross-Chain Staking + --- -Enable users to stake assets on one chain while earning rewards or securing networks on another. + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. -
    -
    + --- -🛠 **Wormhole products used:** + `destinationDomain` ++"uint32"++ - + + Destination domain. -- [**Messaging**](/docs/protocol/infrastructure/){target=\_blank} – moves staking rewards and governance signals across chains -- [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfers staked assets natively between networks + --- -🔗 **Used in:** Liquid staking, cross-chain governance, and PoS networks
    🏗️ **Used by:** [Lido](https://lido.fi/){target=\_blank} + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- -
    -
    ---- END CONTENT --- + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. -Doc-Content: https://wormhole.com/docs/..build/toolkit/cli/ ---- BEGIN CONTENT --- ---- -title: Wormhole CLI -description: Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. -categories: Solidity-SDK, Typescript-SDK ---- +- **`depositForBurnWithCaller`** - deposits and burns tokens from the sender to be minted on the destination domain. This method differs from `depositForBurn` in that the mint on the destination domain can only be called by the designated `destinationCaller` address -# Wormhole CLI + ??? interface "Parameters" -This tool is a command-line interface to Wormhole, allowing you to perform various actions, such as querying a transaction's status or submitting token transfers. + `amount` ++"uint256"++ + + The amount of tokens to burn. -## Installation + --- -Clone the repository and change directories to the appropriate directory: + `destinationDomain` ++"uint32"++ + + The network where the token will be minted after burn. -```bash -git clone https://github.com/wormhole-foundation/wormhole && -cd wormhole/clients/js -``` + --- -Build and install the CLI tool: + `mintRecipient` ++"bytes32"++ + + Address of mint recipient on destination domain. -```bash -make install -``` + --- -This installs two binaries, `worm-fetch-governance` and `worm` on your `$PATH`. To use `worm`, set up `$HOME/.wormhole/.env` with your private keys, based on `.env.sample` in this folder. + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -## Usage + --- -You can interact with the Wormhole CLI by typing `worm` and including the `command` and any necessary subcommands and parameters. + `destinationCaller` ++"bytes32"++ + + Address of the caller on the destination domain who will trigger the mint. -| Command | Description | -|--------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| -| `worm aptos INSERT_COMMAND` | Aptos utilities | -| `worm edit-vaa INSERT_COMMAND` | Edits or generates a VAA | -| `worm evm INSERT_COMMAND` | EVM utilities | -| `worm generate INSERT_COMMAND` | Generate VAAs (Devnet and Testnet only) | -| `worm info INSERT_COMMAND` | Contract, chain, RPC, and address information utilities | -| `worm near INSERT_NETWORK, INSERT_ACCOUNT` | NEAR utilities | -| `worm parse INSERT_VAA` | Parse a VAA (can be in either hex or base64 format) | -| `worm recover INSERT_DIGEST INSERT_SIGNATURE` | Recover an address from a signature | -| `worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH` | Prints information about the automatic delivery initiated on the specified network, chain, and transaction hash | -| `worm submit INSERT_VAA` | Execute a VAA | -| `worm sui INSERT_COMMAND` | Sui utilities | -| `worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK` | Transfers a token | -| `worm verify-vaa INSERT_VAA, INSERT_NETWORK` | Verifies a VAA by querying the Core Contract on Ethereum | + ??? interface "Returns" -You can also refer to the below options, available with all `worm` commands: + `_nonce` ++"uint64"++ + + Unique nonce reserved by message. -```bash -Options: - --help Show help [boolean] - --version Show version number [boolean] -``` + ??? interface "Emits" -### Subcommands + `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called -??? code "Aptos" - ```bash - worm aptos INSERT_COMMAND + ??? child "Event Arguments" -Commands: - worm aptos init-token-bridge Init token bridge contract - worm aptos init-wormhole Init Wormhole core contract - worm aptos deploy Deploy an Aptos package - worm aptos deploy-resource Deploy an Aptos package using a - resource account - worm aptos send-example-message Send example message - - worm aptos derive-resource-account Derive resource account address - - worm aptos derive-wrapped-address Derive wrapped coin type - - worm aptos hash-contracts Hash contract bytecodes for upgrade - worm aptos upgrade Perform upgrade after VAA has been - submitted - worm aptos migrate Perform migration after contract - upgrade - worm aptos faucet Request money from the faucet for a - given account - worm aptos start-validator Start a local aptos validator + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` + --- -??? code "Edit VAA" - ```bash - worm edit-vaa INSERT_COMMAND + `burnToken` ++"address"++ + + Address of token burnt on source domain. -Options: - --help Show help [boolean] - --version Show version number [boolean] - -v, --vaa vaa in hex format [string] [required] - -n, --network Network - [required] [choices: "mainnet", "testnet", "devnet"] - --guardian-set-index, --gsi guardian set index [number] - --signatures, --sigs comma separated list of signatures [string] - --wormscanurl, --wsu url to wormscan entry for the vaa that - includes signatures [string] - --wormscan, --ws if specified, will query the wormscan entry - for the vaa to get the signatures [boolean] - --emitter-chain-id, --ec emitter chain id to be used in the vaa - [number] - --emitter-address, --ea emitter address to be used in the vaa[string] - --nonce, --no nonce to be used in the vaa [number] - --sequence, --seq sequence number to be used in the vaa[string] - --consistency-level, --cl consistency level to be used in the vaa - [number] - --timestamp, --ts timestamp to be used in the vaa in unix - seconds [number] - -p, --payload payload in hex format [string] - --guardian-secret, --gs Guardian's secret key [string] - ``` + --- -??? code "EVM" - ```bash - worm evm INSERT_COMMAND + `amount` ++"uint256"++ + + The deposit amount. -Commands: - worm evm address-from-secret Compute a 20 byte eth address from a 32 - byte private key - worm evm storage-update Update a storage slot on an EVM fork - during testing (anvil or hardhat) - worm evm chains Return all EVM chains - worm evm info Query info about the on-chain state of - the contract - worm evm hijack Override the guardian set of the core - bridge contract during testing (anvil - or hardhat) - worm evm start-validator Start a local EVM validator + --- -Options: - --help Show help [boolean] - --version Show version number [boolean] - --rpc RPC endpoint [string] - ``` + `depositor` ++"address"++ + + Address where deposit is transferred from. -??? code "Generate" - ```bash - worm generate INSERT_COMMAND + --- -Commands: - worm generate registration Generate registration VAA - worm generate upgrade Generate contract upgrade VAA - worm generate attestation Generate a token attestation VAA - worm generate recover-chain-id Generate a recover chain ID VAA - worm generate Sets the default delivery provider - set-default-delivery-provider for the Wormhole Relayer contract + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. -Options: - --help Show help [boolean] - --version Show version number [boolean] - -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] - ``` + --- -??? code "Info" - ```bash - worm info INSERT_COMMAND + `destinationDomain` ++"uint32"++ - + + Destination domain. -Commands: - worm info chain-id Print the wormhole chain ID integer - associated with the specified chain - name - worm info contract Print contract address - - worm info emitter
    Print address in emitter address - format - worm info origin
    Print the origin chain and address - of the asset that corresponds to the - given chain and address. - worm info registrations Print chain registrations - - worm info rpc Print RPC address - worm info wrapped Print the wrapped address on the - target chain that corresponds with - the specified origin chain and - address. + --- -Options: - --help Show help [boolean] - --version Show version number [boolean]
    - ``` + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- -??? code "NEAR" - ```bash - worm near INSERT_COMMAND + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. -Commands: - worm near contract-update Submit a contract update using our specific - APIs - worm near deploy Submit a contract update using near APIs +- **`replaceDepositForBurn`** — replaces a previous `BurnMessage` to modify the mint recipient and/or the destination caller. The replacement message reuses the `_nonce` created by the original message, which allows the original message's sender to update the details without requiring a new deposit -Options: - --help Show help [boolean] - --version Show version number [boolean] - -m, --module Module to query [choices: "Core", "NFTBridge", "TokenBridge"] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - --account Near deployment account [string] [required] - --attach Attach some near [string] - --target Near account to upgrade [string] - --mnemonic Near private keys [string] - --key Near private key [string] - -r, --rpc Override default rpc endpoint url [string] - ``` + ??? interface "Parameters" -??? code "Parse" - ```bash - worm parse INSERT_VAA + `originalMessage` ++"bytes"++ + + The original burn message to be replaced. -Positionals: - vaa vaa [string] + --- -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` + `originalAttestation` ++"bytes"++ + + The attestation of the original message. -??? code "Recover" - ```bash - worm recover INSERT_DIGEST INSERT_SIGNATURE + --- -Positionals: - digest digest [string] - signature signature [string] + `newDestinationCaller` ++"bytes32"++ + + The new caller on the destination domain, can be the same or updated. -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` + --- -??? code "Status" - ```bash - worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH + `newMintRecipient` ++"bytes32"++ + + The new recipient for the minted tokens, can be the same or updated. -Positionals: - network Network [choices: - 'mainnet', - 'testnet', - 'devnet'] - chain Source chain - [choices: - 'unset', - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - tx Source transaction hash [string] + ??? interface "Returns" -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` + None. -??? code "Submit" - ```bash - worm submit INSERT_VAA + ??? interface "Emits" -Positionals: - vaa vaa [string] + `DepositForBurn` - event emitted when `replaceDepositForBurn` is called. Note that the `destinationCaller` will reflect the new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid -Options: - --help Show help [boolean] - --version Show version number [boolean] - -c, --chain chain name -[choices: 'unset', - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - -n, --network Network - [required] - [choices: - 'mainnet', - 'testnet', - 'devnet'] - -a, --contract-address Contract to submit VAA to (override config) [string] - --rpc RPC endpoint [string] - --all-chains, --ac Submit the VAA to all chains except for the origin - chain specified in the payload - [boolean] [default: false] - ``` + ??? child "Event Arguments" -??? code "Sui" - ```bash - worm sui INSERT_COMMAND + `nonce` ++"uint64"++ + + Unique nonce reserved by message (indexed). -Commands: - worm sui build-coin Build wrapped coin and dump bytecode. + --- - Example: - worm sui build-coin -d 8 -v V__0_1_1 -n - testnet -r - "https://fullnode.testnet.sui.io:443" - worm sui deploy Deploy a Sui package - worm sui init-example-message-app Initialize example core message app - worm sui init-token-bridge Initialize token bridge contract - worm sui init-wormhole Initialize wormhole core contract - worm sui publish-example-message Publish message from example app via - core bridge - worm sui setup-devnet Setup devnet by deploying and - initializing core and token bridges and - submitting chain registrations. - worm sui objects Get owned objects by owner - worm sui package-id Get package ID from State object ID - worm sui tx Get transaction details + `burnToken` ++"address"++ + + Address of token burnt on source domain. -Options: - --help Show help [boolean] - --version Show version number [boolean] - ``` + --- -??? code "Transfer" - ```bash - worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK + `amount` ++"uint256"++ + + The deposit amount. -Options: - --help Show help [boolean] - --version Show version number [boolean] - --src-chain source chain [required] [choices: - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - --dst-chain destination chain - [required] [choices: - 'solana', - 'ethereum', - 'terra', - 'bsc', - 'polygon', - 'avalanche', - 'oasis', - 'algorand', - 'aurora', - 'fantom', - 'karura', - 'acala', - 'klaytn', - 'celo', - 'near', - 'moonbeam', - 'neon', - 'terra2', - 'injective', - 'osmosis', - 'sui', - 'aptos', - 'arbitrum', - 'optimism', - 'gnosis', - 'pythnet', - 'xpla', - 'btc', - 'base', - 'sei', - 'rootstock', - 'scroll', - 'mantle', - 'blast', - 'xlayer', - 'linea', - 'berachain', - 'seievm', - 'wormchain', - 'cosmoshub', - 'evmos', - 'kujira', - 'neutron', - 'celestia', - 'stargaze', - 'seda', - 'dymension', - 'provenance', - 'sepolia', - 'arbitrum_sepolia', - 'base_sepolia', - 'optimism_sepolia', - 'holesky', - 'polygon_sepolia'] - --dst-addr destination address [string] [required] - --token-addr token address [string] [default: native token] - --amount token amount [string] [required] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - --rpc RPC endpoint [string] - ``` + --- -??? code "Verify VAA" - ```bash - worm verify-vaa INSERT_VAA, INSERT_NETWORK + `depositor` ++"address"++ + + Address where deposit is transferred from. -Options: - --help Show help [boolean] - --version Show version number [boolean] - -v, --vaa vaa in hex format [string] [required] - -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] - ``` + --- + `mintRecipient` ++"bytes32"++ + + Address receiving minted tokens on destination domain. -## Examples + --- -### VAA generation + `destinationDomain` ++"uint32"++ - + + Destination domain. -Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: + --- -```bash -worm generate registration --module NFTBridge \ - --chain bsc \ - --contract-address 0x706abc4E45D419950511e474C7B9Ed348A4a716c \ - --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 -``` + `destinationTokenMessenger` ++"bytes32"++ + + Address of `TokenMessenger` on destination domain. + + --- -The below example generates a token attestation VAA: + `destinationCaller` ++"bytes32"++ + + Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. -```bash -worm generate attestation --emitter-chain ethereum \ - --emitter-address 11111111111111111111111111111115 \ - --chain ethereum \ - --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ - --decimals 6 \ - --symbol USDC \ - --name USDC \ - --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 -``` +- **`handleReceiveMessage`** - handles an incoming message received by the local `MessageTransmitter` and takes the appropriate action. For a burn message, it mints the associated token to the requested recipient on the local domain. -### VAA parsing + ???+ note -Use `parse` to parse a VAA into JSON: + Though this function can only be called by the local `MessageTransmitter`, it is included here as it emits the essential event for minting tokens and withdrawing to send to the recipient. -```bash -worm parse $(worm-fetch-governance 13940208096455381020) -``` + ??? interface "Parameters" -This example will fetch governance VAA `13940208096455381020` and print it as JSON: + `remoteDomain` ++"uint32"++ + + The domain where the message originated. -```bash -# ...signatures elided -timestamp: 1651416474, -nonce: 1570649151, -emitterChain: 1, -emitterAddress: '0000000000000000000000000000000000000000000000000000000000000004', -sequence: 13940208096455381020n, -consistencyLevel: 32, -payload: { - module: 'Core', - type: 'GuardianSetUpgrade', - chain: 0, - newGuardianSetIndex: 2, - newGuardianSetLength: 19, - newGuardianSet: [ - '58cc3ae5c097b213ce3c81979e1b9f9570746aa5', - 'ff6cb952589bde862c25ef4392132fb9d4a42157', - '114de8460193bdf3a2fcf81f86a09765f4762fd1', - '107a0086b32d7a0977926a205131d8731d39cbeb', - '8c82b2fd82faed2711d59af0f2499d16e726f6b2', - '11b39756c042441be6d8650b69b54ebe715e2343', - '54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd', - '66b9590e1c41e0b226937bf9217d1d67fd4e91f5', - '74a3bf913953d695260d88bc1aa25a4eee363ef0', - '000ac0076727b35fbea2dac28fee5ccb0fea768e', - 'af45ced136b9d9e24903464ae889f5c8a723fc14', - 'f93124b7c738843cbb89e864c862c38cddcccf95', - 'd2cc37a4dc036a8d232b48f62cdd4731412f4890', - 'da798f6896a3331f64b48c12d1d57fd9cbe70811', - '71aa1be1d36cafe3867910f99c09e347899c19c3', - '8192b6e7387ccd768277c17dab1b7a5027c0b3cf', - '178e21ad2e77ae06711549cfbb1f9c7a9d8096e8', - '5e1487f35515d02a92753504a8d75471b9f49edb', - '6fbebc898f403e4773e95feb15e80c9a99c8348d' - ] -} -``` + --- -### Submitting VAAs + `sender` ++"bytes32"++ + + The address of the sender of the message. -Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): + --- -```bash -worm submit $(cat my-nft-registration.txt) --network mainnet -``` + `messageBody` ++"bytes"++ + + The bytes making up the body of the message. -The script will ask you to specify the target chain for VAAs that don't have a specific target chain (like registrations or Guardian set upgrades). For example, to submit a Guardian set upgrade on all chains, simply run: + ??? interface "Returns" -```bash -worm-fetch-governance 13940208096455381020 > guardian-upgrade.txt -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain oasis -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain aurora -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain fantom -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain karura -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain acala -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain klaytn -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain avalanche -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain polygon -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain bsc -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain solana -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain terra -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain ethereum -worm submit $(cat guardian-upgrade.txt) --network mainnet --chain celo -``` + `success` ++"boolean"++ + + Returns `true` if successful, otherwise, it returns `false`. -The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. + ??? interface "Emits" -### Getting Info + `MintAndWithdraw` - event emitted when tokens are minted -To get info about a contract (only EVM supported at this time), use the following command: + ??? child "Event arguments" -```bash -worm evm info -c bsc -n mainnet -m TokenBridge -``` + `localMinter` ++"address"++ + + Minter responsible for minting and burning tokens on the local domain. -Running this command generates the following output: + --- -```bash -{ - "address": "0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "wormhole": "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B", - "implementation": "0x621199f6beB2ba6fbD962E8A52A320EA4F6D4aA3", - "isInitialized": true, - "tokenImplementation": "0x7f8C5e730121657E17E452c5a1bA3fA1eF96f22a", - "chainId": 4, - "finality": 15, - "evmChainId": "56", - "isFork": false, - "governanceChainId": 1, - "governanceContract": "0x0000000000000000000000000000000000000000000000000000000000000004", - "WETH": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", - "registrations": { - "Solana": "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5", - "Ethereum": "0x0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585", - "Terra": "0x0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2", - "Polygon": "0x0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde", - "Avalanche": "0x0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052", - "Oasis": "0x0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564", - "Algorand": "0x67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45", - "Aurora": "0x00000000000000000000000051b5123a7b0f9b2ba265f9c4c8de7d78d52f510f", - "Fantom": "0x0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2", - "Karura": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", - "Acala": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", - "Klaytn": "0x0000000000000000000000005b08ac39eaed75c0439fc750d9fe7e1f9dd0193f", - "Celo": "0x000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed", - "Near": "0x148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7", - "Moonbeam": "0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92", - "Neon": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Terra2": "0xa463ad028fb79679cfc8ce1efba35ac0e77b35080a1abe9bebe83461f176b0a3", - "Injective": "0x00000000000000000000000045dbea4617971d93188eda21530bc6503d153313", - "Osmosis": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Sui": "0xccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5", - "Aptos": "0x0000000000000000000000000000000000000000000000000000000000000001", - "Arbitrum": "0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c", - "Optimism": "0x0000000000000000000000001d68124e65fafc907325e3edbf8c4d84499daa8b", - "Gnosis": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Pythnet": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Xpla": "0x8f9cf727175353b17a5f574270e370776123d90fd74956ae4277962b4fdee24c", - "Btc": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Base": "0x0000000000000000000000008d2de8d2f73f1f4cab472ac9a881c9b123c79627", - "Sei": "0x86c5fd957e2db8389553e1728f9c27964b22a8154091ccba54d75f4b10c61f5e", - "Rootstock": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Scroll": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Mantle": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Blast": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", - "Xlayer": "0x0000000000000000000000005537857664b0f9efe38c9f320f75fef23234d904", - "Linea": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Berachain": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Seievm": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Snaxchain": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Wormchain": "0xaeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924", - "Cosmoshub": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Evmos": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Kujira": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Neutron": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Celestia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Stargaze": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Seda": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Dymension": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Provenance": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "ArbitrumSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "BaseSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "OptimismSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Holesky": "0x0000000000000000000000000000000000000000000000000000000000000000", - "PolygonSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000" - } -} -``` + `remoteDomain` ++"uint32"++ + + The domain where the message originated from. -### Additional Info Examples + --- -You can get the contract address for a module as follows: + `burnToken` ++"address"++ + + Address of contract to burn deposited tokens, on local domain. -```bash -worm info rpc INSERT_NETWORK INSERT_CHAIN INSERT_MODULE -``` + --- -To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can provide the following command: + `mintRecipient` ++"address"++ + + Recipient address of minted tokens (indexed). -```bash -worm info contract mainnet bsc NFTBridge -``` + --- -You can get the RPC address for a chain as follows: + `amount` ++"uint256"++ + + Amount of minted tokens. -```bash -worm info rpc INSERT_NETWORK INSERT_CHAIN -``` +### Message Transmitter Contract -To get the RPC address for BSC Mainnet, for example, you can provide the following command: +The Message Transmitter contract ensures secure messaging across blockchain domains by managing message dispatch and tracking communication with events like `MessageSent` and `MessageReceived`. It uses a unique nonce for each message, which ensures proper validation, verifies attestation signatures, and prevents replay attacks. -```bash -worm info rpc mainnet bsc -``` ---- END CONTENT --- +The contract supports flexible delivery options, allowing messages to be sent to a specific `destinationCaller` or broadcast more generally. It also includes domain-specific configurations to manage communication between chains. -Doc-Content: https://wormhole.com/docs/..build/toolkit/dev-env/ ---- BEGIN CONTENT --- ---- -title: Local Dev Environment -description: Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. -categories: Solidity-SDK, Typescript-SDK ---- +Additional features include replacing previously sent messages, setting maximum message body sizes, and verifying that messages are received only once per nonce to maintain network integrity. -# Development Environment +??? code "Message Transmitter contract" + ```solidity + /* + * Copyright (c) 2022, Circle Internet Financial Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +pragma solidity 0.7.6; -Developers building for smart contract integration will want to set up a development environment to allow testing the full integration, possibly including VAA generation and relaying. +import "@memview-sol/contracts/TypedMemView.sol"; +import "./interfaces/IMessageTransmitter.sol"; +import "./interfaces/IMessageHandler.sol"; +import "./messages/Message.sol"; +import "./roles/Pausable.sol"; +import "./roles/Rescuable.sol"; +import "./roles/Attestable.sol"; -## Tooling Installation +/** + * @title MessageTransmitter + * @notice Contract responsible for sending and receiving messages across chains. + */ +contract MessageTransmitter is + IMessageTransmitter, + Pausable, + Rescuable, + Attestable +{ + // ============ Events ============ + /** + * @notice Emitted when a new message is dispatched + * @param message Raw bytes of message + */ + event MessageSent(bytes message); -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. + /** + * @notice Emitted when a new message is received + * @param caller Caller (msg.sender) on destination domain + * @param sourceDomain The source domain this message originated from + * @param nonce The nonce unique to this message + * @param sender The sender of this message + * @param messageBody message body bytes + */ + event MessageReceived( + address indexed caller, + uint32 sourceDomain, + uint64 indexed nonce, + bytes32 sender, + bytes messageBody + ); -## Development Stages + /** + * @notice Emitted when max message body size is updated + * @param newMaxMessageBodySize new maximum message body size, in bytes + */ + event MaxMessageBodySizeUpdated(uint256 newMaxMessageBodySize); -Different approaches to development and testing are recommended at various stages of application development. + // ============ Libraries ============ + using TypedMemView for bytes; + using TypedMemView for bytes29; + using Message for bytes29; -### Initial Development + // ============ State Variables ============ + // Domain of chain on which the contract is deployed + uint32 public immutable localDomain; -During the initial development of an on-chain application, the best option is to use the native tools available in the environment. You can visit the following resources for more information: + // Message Format version + uint32 public immutable version; -- **[Environment](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - select the folder for the desired network to learn about the recommended native toolset -- **[Mock Guardian](https://github.com/wormhole-foundation/wormhole/blob/main/sdk/js/src/mock/wormhole.ts){target=\_blank}** - it's recommended to set up a mock Guardian or Emitter to provide signed VAAsFor any program methods that require some message be sent or received. -- **[Wormhole Scaffolding repository](https://github.com/wormhole-foundation/wormhole-scaffolding/blob/main/evm/ts-test/01_hello_world.ts){target=\_blank}** - example mock Guardian test + // Maximum size of message body, in bytes. + // This value is set by owner. + uint256 public maxMessageBodySize; -Relying on native tools when possible allows for more rapid prototyping and iteration. + // Next available nonce from this source domain + uint64 public nextAvailableNonce; -### Integration + // Maps a bytes32 hash of (sourceDomain, nonce) -> uint256 (0 if unused, 1 if used) + mapping(bytes32 => uint256) public usedNonces; -For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. - -!!! note - Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. - -### Prepare for Deployment - -Once you've finished the application's initial development and performed integration testing, you should set up a CI test environment. The best option for that is likely to be [Tilt](https://tilt.dev/){target=\_blank} since it allows you to spin up any chains supported by Wormhole in a consistent environment. - -## Validator Setup with Tilt - -### Tilt -If you'd like to set up a local validator environment, follow the setup guide for Tilt. Tilt is a full-fledged Kubernetes deployment of every chain connected to Wormhole, along with a Guardian node. It usually takes 30 minutes to spin up fully, but it comes with all chains running out of the box. Refer to the [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} page for a complete guide to setting up and configuring Tilt. + // ============ Constructor ============ + constructor( + uint32 _localDomain, + address _attester, + uint32 _maxMessageBodySize, + uint32 _version + ) Attestable(_attester) { + localDomain = _localDomain; + maxMessageBodySize = _maxMessageBodySize; + version = _version; + } -## Deploying to Public Networks + // ============ External Functions ============ + /** + * @notice Send the message to the destination domain and recipient + * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. + * @param destinationDomain Domain of destination chain + * @param recipient Address of message recipient on destination chain as bytes32 + * @param messageBody Raw bytes content of message + * @return nonce reserved by message + */ + function sendMessage( + uint32 destinationDomain, + bytes32 recipient, + bytes calldata messageBody + ) external override whenNotPaused returns (uint64) { + bytes32 _emptyDestinationCaller = bytes32(0); + uint64 _nonce = _reserveAndIncrementNonce(); + bytes32 _messageSender = Message.addressToBytes32(msg.sender); -### Testnet + _sendMessage( + destinationDomain, + recipient, + _emptyDestinationCaller, + _messageSender, + _nonce, + messageBody + ); -When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: + return _nonce; + } -```text -https://api.testnet.wormholescan.io -``` + /** + * @notice Replace a message with a new message body and/or destination caller. + * @dev The `originalAttestation` must be a valid attestation of `originalMessage`. + * Reverts if msg.sender does not match sender of original message, or if the source domain of the original message + * does not match this MessageTransmitter's local domain. + * @param originalMessage original message to replace + * @param originalAttestation attestation of `originalMessage` + * @param newMessageBody new message body of replaced message + * @param newDestinationCaller the new destination caller, which may be the + * same as the original destination caller, a new destination caller, or an empty + * destination caller (bytes32(0), indicating that any destination caller is valid.) + */ + function replaceMessage( + bytes calldata originalMessage, + bytes calldata originalAttestation, + bytes calldata newMessageBody, + bytes32 newDestinationCaller + ) external override whenNotPaused { + // Validate each signature in the attestation + _verifyAttestationSignatures(originalMessage, originalAttestation); -### Mainnet + bytes29 _originalMsg = originalMessage.ref(0); -The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: + // Validate message format + _originalMsg._validateMessageFormat(); -```text -https://api.wormholescan.io -``` ---- END CONTENT --- + // Validate message sender + bytes32 _sender = _originalMsg._sender(); + require( + msg.sender == Message.bytes32ToAddress(_sender), + "Sender not permitted to use nonce" + ); -Doc-Content: https://wormhole.com/docs/..build/toolkit/faqs/ ---- BEGIN CONTENT --- ---- -title: Toolkit FAQs -description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. -categories: Solidity-SDK, Typescript-SDK ---- + // Validate source domain + uint32 _sourceDomain = _originalMsg._sourceDomain(); + require( + _sourceDomain == localDomain, + "Message not originally sent from this domain" + ); -# Toolkit FAQs + uint32 _destinationDomain = _originalMsg._destinationDomain(); + bytes32 _recipient = _originalMsg._recipient(); + uint64 _nonce = _originalMsg._nonce(); -## Why does the `toNative` function in the TypeScript SDK return an error? + _sendMessage( + _destinationDomain, + _recipient, + newDestinationCaller, + _sender, + _nonce, + newMessageBody + ); + } -The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. + /** + * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the + * destination domain. + * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. + * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible + * to broadcast the message on the destination domain. This is an advanced feature, and the standard + * sendMessage() should be preferred for use cases where a specific destination caller is not required. + * @param destinationDomain Domain of destination chain + * @param recipient Address of message recipient on destination domain as bytes32 + * @param destinationCaller caller on the destination domain, as bytes32 + * @param messageBody Raw bytes content of message + * @return nonce reserved by message + */ + function sendMessageWithCaller( + uint32 destinationDomain, + bytes32 recipient, + bytes32 destinationCaller, + bytes calldata messageBody + ) external override whenNotPaused returns (uint64) { + require( + destinationCaller != bytes32(0), + "Destination caller must be nonzero" + ); -To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: + uint64 _nonce = _reserveAndIncrementNonce(); + bytes32 _messageSender = Message.addressToBytes32(msg.sender); -```typescript -import solana from '@wormhole-foundation/sdk/solana'; -const wh = await wormhole('Testnet', [solana]); -``` + _sendMessage( + destinationDomain, + recipient, + destinationCaller, + _messageSender, + _nonce, + messageBody + ); -## How can I retrieve the history of previously bridged transactions? + return _nonce; + } -To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: + /** + * @notice Receive a message. Messages with a given nonce + * can only be broadcast once for a (sourceDomain, destinationDomain) + * pair. The message body of a valid message is passed to the + * specified recipient for further processing. + * + * @dev Attestation format: + * A valid attestation is the concatenated 65-byte signature(s) of exactly + * `thresholdSignature` signatures, in increasing order of attester address. + * ***If the attester addresses recovered from signatures are not in + * increasing order, signature verification will fail.*** + * If incorrect number of signatures or duplicate signatures are supplied, + * signature verification will fail. + * + * Message format: + * Field Bytes Type Index + * version 4 uint32 0 + * sourceDomain 4 uint32 4 + * destinationDomain 4 uint32 8 + * nonce 8 uint64 12 + * sender 32 bytes32 20 + * recipient 32 bytes32 52 + * messageBody dynamic bytes 84 + * @param message Message bytes + * @param attestation Concatenated 65-byte signature(s) of `message`, in increasing order + * of the attester address recovered from signatures. + * @return success bool, true if successful + */ + function receiveMessage(bytes calldata message, bytes calldata attestation) + external + override + whenNotPaused + returns (bool success) + { + // Validate each signature in the attestation + _verifyAttestationSignatures(message, attestation); -```bash -https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS -``` + bytes29 _msg = message.ref(0); -Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. + // Validate message format + _msg._validateMessageFormat(); -???- example "Fetch transaction history for a specific address" - ```bash - curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" - ``` + // Validate domain + require( + _msg._destinationDomain() == localDomain, + "Invalid destination domain" + ); -## How can I manually submit a VAA to a destination chain in the correct format? + // Validate destination caller + if (_msg._destinationCaller() != bytes32(0)) { + require( + _msg._destinationCaller() == + Message.addressToBytes32(msg.sender), + "Invalid caller for message" + ); + } -To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: + // Validate version + require(_msg._version() == version, "Invalid message version"); -1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format + // Validate nonce is available + uint32 _sourceDomain = _msg._sourceDomain(); + uint64 _nonce = _msg._nonce(); + bytes32 _sourceAndNonce = _hashSourceAndNonce(_sourceDomain, _nonce); + require(usedNonces[_sourceAndNonce] == 0, "Nonce already used"); + // Mark nonce used + usedNonces[_sourceAndNonce] = 1; - ```bash - https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced - ``` + // Handle receive message + bytes32 _sender = _msg._sender(); + bytes memory _messageBody = _msg._messageBody().clone(); + require( + IMessageHandler(Message.bytes32ToAddress(_msg._recipient())) + .handleReceiveMessage(_sourceDomain, _sender, _messageBody), + "handleReceiveMessage() failed" + ); -2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python + // Emit MessageReceived event + emit MessageReceived( + msg.sender, + _sourceDomain, + _nonce, + _sender, + _messageBody + ); + return true; + } -3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) + /** + * @notice Sets the max message body size + * @dev This value should not be reduced without good reason, + * to avoid impacting users who rely on large messages. + * @param newMaxMessageBodySize new max message body size, in bytes + */ + function setMaxMessageBodySize(uint256 newMaxMessageBodySize) + external + onlyOwner + { + maxMessageBodySize = newMaxMessageBodySize; + emit MaxMessageBodySizeUpdated(maxMessageBodySize); + } - - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section + // ============ Internal Utils ============ + /** + * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0), + * the message can only be received on the destination chain when called by `_destinationCaller`. + * @dev Format the message and emit `MessageSent` event with message information. + * @param _destinationDomain Domain of destination chain + * @param _recipient Address of message recipient on destination domain as bytes32 + * @param _destinationCaller caller on the destination domain, as bytes32 + * @param _sender message sender, as bytes32 + * @param _nonce nonce reserved for message + * @param _messageBody Raw bytes content of message + */ + function _sendMessage( + uint32 _destinationDomain, + bytes32 _recipient, + bytes32 _destinationCaller, + bytes32 _sender, + uint64 _nonce, + bytes calldata _messageBody + ) internal { + // Validate message body length + require( + _messageBody.length <= maxMessageBodySize, + "Message body exceeds max size" + ); - - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field + require(_recipient != bytes32(0), "Recipient must be nonzero"); -Following these steps, you can manually submit a VAA in the proper format to a destination chain. ---- END CONTENT --- + // serialize message + bytes memory _message = Message._formatMessage( + version, + localDomain, + _destinationDomain, + _nonce, + _sender, + _recipient, + _destinationCaller, + _messageBody + ); -Doc-Content: https://wormhole.com/docs/..build/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Interacting with CCTP Contracts -description: Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -categories: Transfer ---- + // Emit MessageSent event + emit MessageSent(_message); + } -# Get Started with CCTP + /** + * @notice hashes `_source` and `_nonce`. + * @param _source Domain of chain where the transfer originated + * @param _nonce The unique identifier for the message from source to + destination + * @return hash of source and nonce + */ + function _hashSourceAndNonce(uint32 _source, uint64 _nonce) + internal + pure + returns (bytes32) + { + return keccak256(abi.encodePacked(_source, _nonce)); + } -## Introduction + /** + * Reserve and increment next available nonce + * @return nonce reserved + */ + function _reserveAndIncrementNonce() internal returns (uint64) { + uint64 _nonceReserved = nextAvailableNonce; + nextAvailableNonce = nextAvailableNonce + 1; + return _nonceReserved; + } +} + ``` -Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. + This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol){target=\_blank} on GitHub. -As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. +The functions provided by the Message Transmitter contract are as follows: -This guide will walk you through getting started with Wormhole's CCTP contracts and show you how to integrate CCTP into your smart contracts, enabling the composition of advanced cross-chain functions with native USDC transfers. +- **`receiveMessage`** — processes and validates an incoming message and its attestation. If valid, it triggers further action based on the message body -## Prerequisites + ??? interface "Parameters" -To interact with the Wormhole CCTP, you'll need the following: + `message` ++"bytes"++ + + The message to be processed, including details such as sender, recipient, and message body. -- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\_blank} on the chains you're deploying your contract on -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on + --- -## Wormhole's CCTP Integration Contract + `attestation` ++"bytes"++ + + Concatenated 65-byte signature(s) that attest to the validity of the `message`. -Wormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract you'll interact with directly. It burns and mints Circle-supported tokens by using [Circle's CCTP contracts](#circles-cctp-contracts). + ??? interface "Returns" -The Circle Integration contract emits Wormhole messages with arbitrary payloads to allow additional composability when performing cross-chain transfers of Circle-supported assets. + `success` ++"boolean"++ + + Returns `true` if successful, otherwise, returns `false`. -This contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\_blank} on GitHub. + ??? interface "Emits" -!!! note - Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank}. Please refer to the [CCTP section of the Contract Addresses](/docs/products/reference/contract-addresses/#cctp){target=\_blank} reference page to view the complete list of supported chains. + `MessageReceived` - event emitted when a new message is received -??? code "Circle Integration contract" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.19; + ??? child "Event arguments" -import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IWormhole} from "wormhole/interfaces/IWormhole.sol"; -import {BytesLib} from "wormhole/libraries/external/BytesLib.sol"; + `caller` ++"address"++ + + Caller on destination domain. -import {ICircleBridge} from "../interfaces/circle/ICircleBridge.sol"; + --- -import {CircleIntegrationGovernance} from "./CircleIntegrationGovernance.sol"; -import {CircleIntegrationMessages} from "./CircleIntegrationMessages.sol"; + `sourceDomain` ++"uint32"++ + + The source domain this message originated from. -/** - * @notice This contract burns and mints Circle-supported tokens by using Circle's Cross-Chain Transfer Protocol. It also emits - * Wormhole messages with arbitrary payloads to allow for additional composability when performing cross-chain - * transfers of Circle-suppored assets. - */ -contract CircleIntegration is - CircleIntegrationMessages, - CircleIntegrationGovernance, - ReentrancyGuard -{ - using BytesLib for bytes; + --- - /** - * @notice Emitted when Circle-supported assets have been minted to the mintRecipient - * @param emitterChainId Wormhole chain ID of emitter contract on source chain - * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on source chain - * @param sequence Sequence of Wormhole message used to mint tokens - */ - event Redeemed( - uint16 indexed emitterChainId, - bytes32 indexed emitterAddress, - uint64 indexed sequence - ); + `nonce` ++"uint64"++ + + Nonce unique to this message (indexed). - /** - * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits - * a Wormhole message containing a user-specified payload with instructions for what to do with - * the Circle-supported assets once they have been minted on the target chain. - * @dev reverts if: - * - user passes insufficient value to pay Wormhole message fee - * - `token` is not supported by Circle Bridge - * - `amount` is zero - * - `targetChain` is not supported - * - `mintRecipient` is bytes32(0) - * @param transferParams Struct containing the following attributes: - * - `token` Address of the token to be burned - * - `amount` Amount of `token` to be burned - * - `targetChain` Wormhole chain ID of the target blockchain - * - `mintRecipient` The recipient wallet or contract address on the target chain - * @param batchId ID for Wormhole message batching - * @param payload Arbitrary payload to be delivered to the target chain via Wormhole - * @return messageSequence Wormhole sequence number for this contract - */ - function transferTokensWithPayload( - TransferParameters memory transferParams, - uint32 batchId, - bytes memory payload - ) public payable nonReentrant returns (uint64 messageSequence) { - // cache wormhole instance and fees to save on gas - IWormhole wormhole = wormhole(); - uint256 wormholeFee = wormhole.messageFee(); + --- - // confirm that the caller has sent enough ether to pay for the wormhole message fee - require(msg.value == wormholeFee, "insufficient value"); + `sender` ++"bytes32"++ + + Sender of this message. - // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient` - // should be the target contract (or wallet) composing on this contract. - (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}( - transferParams.token, - transferParams.amount, - transferParams.targetChain, - transferParams.mintRecipient - ); + --- - // encode DepositWithPayload message - bytes memory encodedMessage = encodeDepositWithPayload( - DepositWithPayload({ - token: addressToBytes32(transferParams.token), - amount: amountReceived, - sourceDomain: localDomain(), - targetDomain: getDomainFromChainId(transferParams.targetChain), - nonce: nonce, - fromAddress: addressToBytes32(msg.sender), - mintRecipient: transferParams.mintRecipient, - payload: payload - }) - ); + `messageBody` ++"bytes"++ + + The body of the message. - // send the DepositWithPayload wormhole message - messageSequence = wormhole.publishMessage{value: wormholeFee}( - batchId, - encodedMessage, - wormholeFinality() - ); - } +- **`sendMessage`** — sends a message to the destination domain and recipient. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event - function _transferTokens( - address token, - uint256 amount, - uint16 targetChain, - bytes32 mintRecipient - ) internal returns (uint64 nonce, uint256 amountReceived) { - // sanity check user input - require(amount > 0, "amount must be > 0"); - require(mintRecipient != bytes32(0), "invalid mint recipient"); - require(isAcceptedToken(token), "token not accepted"); - require( - getRegisteredEmitter(targetChain) != bytes32(0), - "target contract not registered" - ); + ??? interface "Parameters" - // take custody of tokens - amountReceived = custodyTokens(token, amount); + `destinationDomain` ++"uint32"++ + + The target blockchain network where the message is to be sent. - // cache Circle Bridge instance - ICircleBridge circleBridge = circleBridge(); + --- - // approve the Circle Bridge to spend tokens - SafeERC20.safeApprove( - IERC20(token), - address(circleBridge), - amountReceived - ); - - // burn tokens on the bridge - nonce = circleBridge.depositForBurnWithCaller( - amountReceived, - getDomainFromChainId(targetChain), - mintRecipient, - token, - getRegisteredEmitter(targetChain) - ); - } + `recipient` ++"bytes32"++ + + The recipient's address on the destination domain. - function custodyTokens( - address token, - uint256 amount - ) internal returns (uint256) { - // query own token balance before transfer - (, bytes memory queriedBalanceBefore) = token.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) - ); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); + --- - // deposit tokens - SafeERC20.safeTransferFrom( - IERC20(token), - msg.sender, - address(this), - amount - ); + `messageBody` ++"bytes"++ + + The raw bytes content of the message. - // query own token balance after transfer - (, bytes memory queriedBalanceAfter) = token.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) - ); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); + ??? interface "Returns" - return balanceAfter - balanceBefore; - } + `nonce` ++"uint64"++ + + Nonce unique to this message. - /** - * @notice `redeemTokensWithPayload` verifies the Wormhole message from the source chain and - * verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge - * contract by passing the Circle message and attestation to mint tokens to the specified - * mint recipient. It also verifies that the caller is the specified mint recipient to ensure - * atomic execution of the additional instructions in the Wormhole message. - * @dev reverts if: - * - Wormhole message is not properly attested - * - Wormhole message was not emitted from a registered contrat - * - Wormhole message was already consumed by this contract - * - msg.sender is not the encoded mintRecipient - * - Circle Bridge message and Wormhole message are not associated - * - `receiveMessage` call to Circle Transmitter fails - * @param params Struct containing the following attributes: - * - `encodedWormholeMessage` Wormhole message emitted by a registered contract including - * information regarding the token burn on the source chain and an arbitrary message. - * - `circleBridgeMessage` Message emitted by Circle Bridge contract with information regarding - * the token burn on the source chain. - * - `circleAttestation` Serialized EC Signature attesting the cross-chain transfer - * @return depositInfo Struct containing the following attributes: - * - `token` Address (bytes32 left-zero-padded) of token to be minted - * - `amount` Amount of tokens to be minted - * - `sourceDomain` Circle domain for the source chain - * - `targetDomain` Circle domain for the target chain - * - `nonce` Circle sequence number for the transfer - * - `fromAddress` Source CircleIntegration contract caller's address - * - `mintRecipient` Recipient of minted tokens (must be caller of this contract) - * - `payload` Arbitrary Wormhole message payload - */ - function redeemTokensWithPayload( - RedeemParameters calldata params - ) public returns (DepositWithPayload memory depositInfo) { - // verify the wormhole message - IWormhole.VM memory verifiedMessage = verifyWormholeRedeemMessage( - params.encodedWormholeMessage - ); + ??? interface "Emits" - // Decode the message payload into the DepositWithPayload struct. Call the Circle TokenMinter - // contract to determine the address of the encoded token on this chain. - depositInfo = decodeDepositWithPayload(verifiedMessage.payload); - depositInfo.token = fetchLocalTokenAddress( - depositInfo.sourceDomain, - depositInfo.token - ); + `MessageSent` - event emitted when a new message is dispatched - // confirm that circle gave us a valid token address - require(depositInfo.token != bytes32(0), "invalid local token address"); +??? child "Event arguments" - // confirm that the caller is the `mintRecipient` to ensure atomic execution - require( - addressToBytes32(msg.sender) == depositInfo.mintRecipient, - "caller must be mintRecipient" - ); + `message` ++"bytes"++ + + The raw bytes of the message. - // confirm that the caller passed the correct message pair - require( - verifyCircleMessage( - params.circleBridgeMessage, - depositInfo.sourceDomain, - depositInfo.targetDomain, - depositInfo.nonce - ), - "invalid message pair" - ); +- **`sendMessageWithCaller`** — sends a message to the destination domain and recipient, requiring a specific caller to trigger the message on the target chain. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event - // call the circle bridge to mint tokens to the recipient - bool success = circleTransmitter().receiveMessage( - params.circleBridgeMessage, - params.circleAttestation - ); - require(success, "CIRCLE_INTEGRATION: failed to mint tokens"); + ??? interface "Parameters" - // emit Redeemed event - emit Redeemed( - verifiedMessage.emitterChainId, - verifiedMessage.emitterAddress, - verifiedMessage.sequence - ); - } + `destinationDomain` ++"uint32"++ + + The target blockchain network where the message is to be sent. - function verifyWormholeRedeemMessage( - bytes memory encodedMessage - ) internal returns (IWormhole.VM memory) { - require(evmChain() == block.chainid, "invalid evm chain"); + --- - // parse and verify the Wormhole core message - ( - IWormhole.VM memory verifiedMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); + `recipient` ++"bytes32"++ + + The recipient's address on the destination domain. - // confirm that the core layer verified the message - require(valid, reason); + --- - // verify that this message was emitted by a trusted contract - require(verifyEmitter(verifiedMessage), "unknown emitter"); + `destinationCaller` ++"bytes32"++ + + The caller on the destination domain. - // revert if this message has been consumed already - require( - !isMessageConsumed(verifiedMessage.hash), - "message already consumed" - ); - consumeMessage(verifiedMessage.hash); + --- - return verifiedMessage; - } + `messageBody` ++"bytes"++ + + The raw bytes content of the message. - function verifyEmitter( - IWormhole.VM memory vm - ) internal view returns (bool) { - // verify that the sender of the wormhole message is a trusted - return (getRegisteredEmitter(vm.emitterChainId) == vm.emitterAddress && - vm.emitterAddress != bytes32(0)); - } + ??? interface "Returns" - function verifyCircleMessage( - bytes memory circleMessage, - uint32 sourceDomain, - uint32 targetDomain, - uint64 nonce - ) internal pure returns (bool) { - // parse the circle bridge message inline - uint32 circleSourceDomain = circleMessage.toUint32(4); - uint32 circleTargetDomain = circleMessage.toUint32(8); - uint64 circleNonce = circleMessage.toUint64(12); + `nonce` ++"uint64"++ + + Nonce unique to this message. - // confirm that both the Wormhole message and Circle message share the same transfer info - return (sourceDomain == circleSourceDomain && - targetDomain == circleTargetDomain && - nonce == circleNonce); - } + ??? interface "Emits" - /** - * @notice Fetches the local token address given an address and domain from - * a different chain. - * @param sourceDomain Circle domain for the sending chain. - * @param sourceToken Address of the token for the sending chain. - * @return Address bytes32 formatted address of the `sourceToken` on this chain. - */ - function fetchLocalTokenAddress( - uint32 sourceDomain, - bytes32 sourceToken - ) public view returns (bytes32) { - return - addressToBytes32( - circleTokenMinter().remoteTokensToLocalTokens( - keccak256(abi.encodePacked(sourceDomain, sourceToken)) - ) - ); - } + `MessageSent` - event emitted when a new message is dispatched - /** - * @notice Converts type address to bytes32 (left-zero-padded) - * @param address_ Address to convert to bytes32 - * @return Address bytes32 - */ - function addressToBytes32(address address_) public pure returns (bytes32) { - return bytes32(uint256(uint160(address_))); - } -} - ``` +??? child "Event arguments" -The functions provided by the Circle Integration contract are as follows: + `message` ++"bytes"++ + + The raw bytes of the message. -- **`transferTokensWithPayload`** - calls the Circle Bridge contract to burn Circle-supported tokens. It emits a Wormhole message containing a user-specified payload with instructions for what to do with the Circle-supported assets once they have been minted on the target chain +- **`replaceMessage`** — replaces an original message with a new message body and/or updates the destination caller. The replacement message reuses the `_nonce` created by the original message ??? interface "Parameters" - `transferParams` ++"TransferParameters"++ + `originalMessage` ++"bytes"++ + + The original message to be replaced. - A tuple containing the parameters for the transfer. + --- - ??? child "`TransferParameters` struct" + `originalAttestation` ++"bytes"++ + + Attestation verifying the original message. - `token` ++"address"++ + --- - Address of the token to be burned. + `newMessageBody` ++"bytes"++ + + The new content for the replaced message. - --- + --- - `amount` ++"uint256"++ + `newDestinationCaller` ++"bytes32"++ + + The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid. - Amount of the token to be burned. + ??? interface "Returns" - --- - - `targetChain` ++"uint16"++ - - Wormhole chain ID of the target blockchain. - - --- - - `mintRecipient` ++"bytes32"++ - - The recipient wallet or contract address on the target chain. - - --- - - `batchId` ++"uint32"++ - - The ID for Wormhole message batching. - - --- - - `payload` ++"bytes"++ - - Arbitrary payload to be delivered to the target chain via Wormhole. - - ??? interface "Returns" - - `messageSequence` ++"uint64"++ - - Wormhole sequence number for this contract. - -- `redeemTokensWithPayload` - verifies the Wormhole message from the source chain and verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge contract by passing the Circle message and attestation to the `receiveMessage` function, which is responsible for minting tokens to the specified mint recipient. It also verifies that the caller is the specified mint recipient to ensure atomic execution of the additional instructions in the Wormhole message - - ??? interface "Parameters" - - `params` ++"RedeemParameters"++ - - A tuple containing the parameters for the redemption. - - ??? child "`RedeemParameters` struct" - - `encodedWormholeMessage` ++"bytes"++ - - Wormhole message emitted by a registered contract including information regarding the token burn on the source chain and an arbitrary message. - - --- - - `circleBridgeMessage` ++"bytes"++ - - Message emitted by Circle Bridge contract with information regarding the token burn on the source chain. - - --- - - `circleAttestation` ++"bytes"++ - - Serialized EC signature attesting the cross-chain transfer. - - ??? interface "Returns" - - `depositInfo` ++"DepositWithPayload"++ - - Information about the deposit. - - ??? child "`DepositWithPayload` struct" - - `token` ++"bytes32"++ - - Address (`bytes32` left-zero-padded) of token to be minted. - - --- - - `amount` ++"uint256"++ - - Amount of tokens to be minted. - - --- - - `sourceDomain` ++"uint32"++ - - Circle domain for the source chain. - - --- - - `targetDomain` ++"uint32"++ - - Circle domain for the target chain. - - --- - - `nonce` ++"uint64"++ - - Circle sequence number for the transfer. - - --- - - `fromAddress` ++"bytes32"++ - - Source Circle Integration contract caller's address. - - --- - - `mintRecipient` ++"bytes32"++ - - Recipient of minted tokens (must be caller of this contract). - - --- - - `payload` ++"bytes"++ - - Arbitrary Wormhole message payload. + None. ??? interface "Emits" - `Redeemed` - event emitted when Circle-supported assets have been minted to the `mintRecipient` - - ??? child "Event arguments" - - `emitterChainId` ++"uint16"++ - - Wormhole chain ID of emitter contract on source chain. - - --- - - `emitterAddress` ++"bytes32"++ - - Address (`bytes32` zero-left-padded) of emitter on source chain. - - --- - - `sequence` ++"uint64"++ - - Sequence of Wormhole message used to mint tokens. - -## Circle's CCTP Contracts - -Three key contracts power Circle's CCTP: - -- **`TokenMessenger`** - the entry point for cross-chain USDC transfers, routing messages to initiate USDC burns on the source chain, and mint USDC on the destination chain -- **`MessageTransmitter`** - handles generic message passing, sending messages from the source chain and receiving them on the destination chain -- **`TokenMinter`** - responsible for the actual minting and burning of USDC, utilizing chain-specific settings for both the burners and minters across different networks - -The following sections will examine these contracts in-depth, focusing on the methods invoked indirectly through function calls in the Wormhole Circle Integration contract. + `MessageSent` - event emitted when a new message is dispatched -!!! note - When using Wormhole's CCTP integration, you will not directly interact with these contracts. You will indirectly interact with them through the Wormhole Circle Integration contract. +??? child "Event arguments" -These contracts can be found in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/){target=\_blank} on GitHub. + `message` ++"bytes"++ + + The raw bytes of the message. -### Token Messenger Contract +### Token Minter Contract -The Token Messenger contract enables cross-chain USDC transfers by coordinating message exchanges between blockchains. It works alongside the Message Transmitter contract to relay messages for burning USDC on a source chain and minting it on a destination chain. The contract emits events to track both the burning of tokens and their subsequent minting on the destination chain. +The Token Minter contract manages the minting and burning of tokens across different blockchain domains. It maintains a registry that links local tokens to their corresponding remote tokens, ensuring that tokens maintain a 1:1 exchange rate across domains. -To ensure secure communication, the Token Messenger restricts message handling to registered remote Token Messenger contracts only. It verifies the proper conditions for token burning and manages local and remote minters using chain-specific settings. +The contract restricts minting and burning functions to a designated Token Messenger, which ensures secure and reliable cross-chain operations. When tokens are burned on a remote domain, an equivalent amount is minted on the local domain for a specified recipient, and vice versa. -Additionally, the contract provides methods for updating or replacing previously sent burn messages, adding or removing remote Token Messenger contracts, and managing the minting process for cross-chain transfers. +To enhance control and flexibility, the contract includes mechanisms to pause operations, set burn limits, and update the Token Controller, which governs token minting permissions. Additionally, it provides functionality to add or remove the local Token Messenger and retrieve the local token address associated with a remote token. -??? code "Token Messenger contract" +??? code "Token Minter contract" ```solidity /* * Copyright (c) 2022, Circle Internet Financial Limited. @@ -2515,19205 +2441,17727 @@ Additionally, the contract provides methods for updating or replacing previously */ pragma solidity 0.7.6; -import "./interfaces/IMessageHandler.sol"; import "./interfaces/ITokenMinter.sol"; import "./interfaces/IMintBurnToken.sol"; -import "./interfaces/IMessageTransmitter.sol"; -import "./messages/BurnMessage.sol"; -import "./messages/Message.sol"; +import "./roles/Pausable.sol"; import "./roles/Rescuable.sol"; +import "./roles/TokenController.sol"; +import "./TokenMessenger.sol"; /** - * @title TokenMessenger - * @notice Sends messages and receives messages to/from MessageTransmitters - * and to/from TokenMinters + * @title TokenMinter + * @notice Token Minter and Burner + * @dev Maintains registry of local mintable tokens and corresponding tokens on remote domains. + * This registry can be used by caller to determine which token on local domain to mint for a + * burned token on a remote domain, and vice versa. + * It is assumed that local and remote tokens are fungible at a constant 1:1 exchange rate. */ -contract TokenMessenger is IMessageHandler, Rescuable { +contract TokenMinter is ITokenMinter, TokenController, Pausable, Rescuable { // ============ Events ============ /** - * @notice Emitted when a DepositForBurn message is sent - * @param nonce unique nonce reserved by message - * @param burnToken address of token burnt on source domain - * @param amount deposit amount - * @param depositor address where deposit is transferred from - * @param mintRecipient address receiving minted tokens on destination domain as bytes32 - * @param destinationDomain destination domain - * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32 - * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). - * If equal to bytes32(0), any address can call receiveMessage(). + * @notice Emitted when a local TokenMessenger is added + * @param localTokenMessenger address of local TokenMessenger + * @notice Emitted when a local TokenMessenger is added */ - event DepositForBurn( - uint64 indexed nonce, - address indexed burnToken, - uint256 amount, - address indexed depositor, - bytes32 mintRecipient, - uint32 destinationDomain, - bytes32 destinationTokenMessenger, - bytes32 destinationCaller - ); + event LocalTokenMessengerAdded(address localTokenMessenger); /** - * @notice Emitted when tokens are minted - * @param mintRecipient recipient address of minted tokens - * @param amount amount of minted tokens - * @param mintToken contract address of minted token + * @notice Emitted when a local TokenMessenger is removed + * @param localTokenMessenger address of local TokenMessenger + * @notice Emitted when a local TokenMessenger is removed */ - event MintAndWithdraw( - address indexed mintRecipient, - uint256 amount, - address indexed mintToken - ); + event LocalTokenMessengerRemoved(address localTokenMessenger); - /** - * @notice Emitted when a remote TokenMessenger is added - * @param domain remote domain - * @param tokenMessenger TokenMessenger on remote domain - */ - event RemoteTokenMessengerAdded(uint32 domain, bytes32 tokenMessenger); + // ============ State Variables ============ + // Local TokenMessenger with permission to call mint and burn on this TokenMinter + address public localTokenMessenger; + // ============ Modifiers ============ /** - * @notice Emitted when a remote TokenMessenger is removed - * @param domain remote domain - * @param tokenMessenger TokenMessenger on remote domain + * @notice Only accept messages from the registered message transmitter on local domain */ - event RemoteTokenMessengerRemoved(uint32 domain, bytes32 tokenMessenger); + modifier onlyLocalTokenMessenger() { + require(_isLocalTokenMessenger(), "Caller not local TokenMessenger"); + _; + } + // ============ Constructor ============ /** - * @notice Emitted when the local minter is added - * @param localMinter address of local minter - * @notice Emitted when the local minter is added + * @param _tokenController Token controller address */ - event LocalMinterAdded(address localMinter); + constructor(address _tokenController) { + _setTokenController(_tokenController); + } + // ============ External Functions ============ /** - * @notice Emitted when the local minter is removed - * @param localMinter address of local minter - * @notice Emitted when the local minter is removed + * @notice Mints `amount` of local tokens corresponding to the + * given (`sourceDomain`, `burnToken`) pair, to `to` address. + * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not + * map to a nonzero local token address. This mapping can be queried using + * getLocalToken(). + * @param sourceDomain Source domain where `burnToken` was burned. + * @param burnToken Burned token address as bytes32. + * @param to Address to receive minted tokens, corresponding to `burnToken`, + * on this domain. + * @param amount Amount of tokens to mint. Must be less than or equal + * to the minterAllowance of this TokenMinter for given `_mintToken`. + * @return mintToken token minted. */ - event LocalMinterRemoved(address localMinter); - - // ============ Libraries ============ - using TypedMemView for bytes; - using TypedMemView for bytes29; - using BurnMessage for bytes29; - using Message for bytes29; - - // ============ State Variables ============ - // Local Message Transmitter responsible for sending and receiving messages to/from remote domains - IMessageTransmitter public immutable localMessageTransmitter; - - // Version of message body format - uint32 public immutable messageBodyVersion; - - // Minter responsible for minting and burning tokens on the local domain - ITokenMinter public localMinter; + function mint( + uint32 sourceDomain, + bytes32 burnToken, + address to, + uint256 amount + ) + external + override + whenNotPaused + onlyLocalTokenMessenger + returns (address mintToken) + { + address _mintToken = _getLocalToken(sourceDomain, burnToken); + require(_mintToken != address(0), "Mint token not supported"); + IMintBurnToken _token = IMintBurnToken(_mintToken); - // Valid TokenMessengers on remote domains - mapping(uint32 => bytes32) public remoteTokenMessengers; + require(_token.mint(to, amount), "Mint operation failed"); + return _mintToken; + } - // ============ Modifiers ============ /** - * @notice Only accept messages from a registered TokenMessenger contract on given remote domain - * @param domain The remote domain - * @param tokenMessenger The address of the TokenMessenger contract for the given remote domain + * @notice Burn tokens owned by this TokenMinter. + * @param burnToken burnable token address. + * @param burnAmount amount of tokens to burn. Must be + * > 0, and <= maximum burn amount per message. */ - modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) { - require( - _isRemoteTokenMessenger(domain, tokenMessenger), - "Remote TokenMessenger unsupported" - ); - _; + function burn(address burnToken, uint256 burnAmount) + external + override + whenNotPaused + onlyLocalTokenMessenger + onlyWithinBurnLimit(burnToken, burnAmount) + { + IMintBurnToken _token = IMintBurnToken(burnToken); + _token.burn(burnAmount); } /** - * @notice Only accept messages from the registered message transmitter on local domain + * @notice Add TokenMessenger for the local domain. Only this TokenMessenger + * has permission to call mint() and burn() on this TokenMinter. + * @dev Reverts if a TokenMessenger is already set for the local domain. + * @param newLocalTokenMessenger The address of the new TokenMessenger on the local domain. */ - modifier onlyLocalMessageTransmitter() { - // Caller must be the registered message transmitter for this domain - require(_isLocalMessageTransmitter(), "Invalid message transmitter"); - _; + function addLocalTokenMessenger(address newLocalTokenMessenger) + external + onlyOwner + { + require( + newLocalTokenMessenger != address(0), + "Invalid TokenMessenger address" + ); + + require( + localTokenMessenger == address(0), + "Local TokenMessenger already set" + ); + + localTokenMessenger = newLocalTokenMessenger; + + emit LocalTokenMessengerAdded(localTokenMessenger); } - // ============ Constructor ============ /** - * @param _messageTransmitter Message transmitter address - * @param _messageBodyVersion Message body version + * @notice Remove the TokenMessenger for the local domain. + * @dev Reverts if the TokenMessenger of the local domain is not set. */ - constructor(address _messageTransmitter, uint32 _messageBodyVersion) { + function removeLocalTokenMessenger() external onlyOwner { + address _localTokenMessengerBeforeRemoval = localTokenMessenger; require( - _messageTransmitter != address(0), - "MessageTransmitter not set" + _localTokenMessengerBeforeRemoval != address(0), + "No local TokenMessenger is set" ); - localMessageTransmitter = IMessageTransmitter(_messageTransmitter); - messageBodyVersion = _messageBodyVersion; + + delete localTokenMessenger; + emit LocalTokenMessengerRemoved(_localTokenMessengerBeforeRemoval); } - // ============ External Functions ============ /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. - * Emits a `DepositForBurn` event. - * @dev reverts if: - * - given burnToken is not supported - * - given destinationDomain has no TokenMessenger registered - * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance - * to this contract is less than `amount`. - * - burn() reverts. For example, if `amount` is 0. - * - MessageTransmitter returns false or reverts. - * @param amount amount of tokens to burn - * @param destinationDomain destination domain - * @param mintRecipient address of mint recipient on destination domain - * @param burnToken address of contract to burn deposited tokens, on local domain - * @return _nonce unique nonce reserved by message + * @notice Set tokenController to `newTokenController`, and + * emit `SetTokenController` event. + * @dev newTokenController must be nonzero. + * @param newTokenController address of new token controller */ - function depositForBurn( - uint256 amount, - uint32 destinationDomain, - bytes32 mintRecipient, - address burnToken - ) external returns (uint64 _nonce) { - return - _depositForBurn( - amount, - destinationDomain, - mintRecipient, - burnToken, - // (bytes32(0) here indicates that any address can call receiveMessage() - // on the destination domain, triggering mint to specified `mintRecipient`) - bytes32(0) - ); + function setTokenController(address newTokenController) + external + override + onlyOwner + { + _setTokenController(newTokenController); } /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint - * on the destination domain must be called by `destinationCaller`. - * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible - * to broadcast the message on the destination domain. This is an advanced feature, and the standard - * depositForBurn() should be preferred for use cases where a specific destination caller is not required. - * Emits a `DepositForBurn` event. - * @dev reverts if: - * - given destinationCaller is zero address - * - given burnToken is not supported - * - given destinationDomain has no TokenMessenger registered - * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance - * to this contract is less than `amount`. - * - burn() reverts. For example, if `amount` is 0. - * - MessageTransmitter returns false or reverts. - * @param amount amount of tokens to burn - * @param destinationDomain destination domain - * @param mintRecipient address of mint recipient on destination domain - * @param burnToken address of contract to burn deposited tokens, on local domain - * @param destinationCaller caller on the destination domain, as bytes32 - * @return nonce unique nonce reserved by message + * @notice Get the local token address associated with the given + * remote domain and token. + * @param remoteDomain Remote domain + * @param remoteToken Remote token + * @return local token address */ - function depositForBurnWithCaller( - uint256 amount, - uint32 destinationDomain, - bytes32 mintRecipient, - address burnToken, - bytes32 destinationCaller - ) external returns (uint64 nonce) { - // Destination caller must be nonzero. To allow any destination caller, use depositForBurn(). - require(destinationCaller != bytes32(0), "Invalid destination caller"); - - return - _depositForBurn( - amount, - destinationDomain, - mintRecipient, - burnToken, - destinationCaller - ); + function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) + external + view + override + returns (address) + { + return _getLocalToken(remoteDomain, remoteToken); } + // ============ Internal Utils ============ /** - * @notice Replace a BurnMessage to change the mint recipient and/or - * destination caller. Allows the sender of a previous BurnMessage - * (created by depositForBurn or depositForBurnWithCaller) - * to send a new BurnMessage to replace the original. - * The new BurnMessage will reuse the amount and burn token of the original, - * without requiring a new deposit. - * @dev The new message will reuse the original message's nonce. For a - * given nonce, all replacement message(s) and the original message are - * valid to broadcast on the destination domain, until the first message - * at the nonce confirms, at which point all others are invalidated. - * Note: The msg.sender of the replaced message must be the same as the - * msg.sender of the original message. - * @param originalMessage original message bytes (to replace) - * @param originalAttestation original attestation bytes - * @param newDestinationCaller the new destination caller, which may be the - * same as the original destination caller, a new destination caller, or an empty - * destination caller (bytes32(0), indicating that any destination caller is valid.) - * @param newMintRecipient the new mint recipient, which may be the same as the - * original mint recipient, or different. + * @notice Returns true if the message sender is the registered local TokenMessenger + * @return True if the message sender is the registered local TokenMessenger */ - function replaceDepositForBurn( - bytes calldata originalMessage, - bytes calldata originalAttestation, - bytes32 newDestinationCaller, - bytes32 newMintRecipient - ) external { - bytes29 _originalMsg = originalMessage.ref(0); - _originalMsg._validateMessageFormat(); - bytes29 _originalMsgBody = _originalMsg._messageBody(); - _originalMsgBody._validateBurnMessageFormat(); + function _isLocalTokenMessenger() internal view returns (bool) { + return + address(localTokenMessenger) != address(0) && + msg.sender == address(localTokenMessenger); + } +} + ``` - bytes32 _originalMsgSender = _originalMsgBody._getMessageSender(); - // _originalMsgSender must match msg.sender of original message - require( - msg.sender == Message.bytes32ToAddress(_originalMsgSender), - "Invalid sender for message" - ); - require( - newMintRecipient != bytes32(0), - "Mint recipient must be nonzero" - ); + This contract and the interfaces and contracts it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMinter.sol){target=\_blank} on GitHub. - bytes32 _burnToken = _originalMsgBody._getBurnToken(); - uint256 _amount = _originalMsgBody._getAmount(); +Most of the methods of the Token Minter contract can be called only by the registered Token Messenger. However, there is one publicly accessible method, a public view function that allows anyone to query the local token associated with a remote domain and token. - bytes memory _newMessageBody = BurnMessage._formatMessage( - messageBodyVersion, - _burnToken, - newMintRecipient, - _amount, - _originalMsgSender - ); +- **`getLocalToken`** — a read-only function that returns the local token address associated with a given remote domain and token - localMessageTransmitter.replaceMessage( - originalMessage, - originalAttestation, - _newMessageBody, - newDestinationCaller - ); + ??? interface "Parameters" - emit DepositForBurn( - _originalMsg._nonce(), - Message.bytes32ToAddress(_burnToken), - _amount, - msg.sender, - newMintRecipient, - _originalMsg._destinationDomain(), - _originalMsg._recipient(), - newDestinationCaller - ); - } + `remoteDomain` ++"uint32"++ + + The remote blockchain domain where the token resides. - /** - * @notice Handles an incoming message received by the local MessageTransmitter, - * and takes the appropriate action. For a burn message, mints the - * associated token to the requested recipient on the local domain. - * @dev Validates the local sender is the local MessageTransmitter, and the - * remote sender is a registered remote TokenMessenger for `remoteDomain`. - * @param remoteDomain The domain where the message originated from. - * @param sender The sender of the message (remote TokenMessenger). - * @param messageBody The message body bytes. - * @return success Bool, true if successful. - */ - function handleReceiveMessage( - uint32 remoteDomain, - bytes32 sender, - bytes calldata messageBody - ) - external - override - onlyLocalMessageTransmitter - onlyRemoteTokenMessenger(remoteDomain, sender) - returns (bool) - { - bytes29 _msg = messageBody.ref(0); - _msg._validateBurnMessageFormat(); - require( - _msg._getVersion() == messageBodyVersion, - "Invalid message body version" - ); + --- - bytes32 _mintRecipient = _msg._getMintRecipient(); - bytes32 _burnToken = _msg._getBurnToken(); - uint256 _amount = _msg._getAmount(); + `remoteToken` ++"bytes32"++ + + The address of the token on the remote domain. - ITokenMinter _localMinter = _getLocalMinter(); + ??? interface "Returns" - _mintAndWithdraw( - address(_localMinter), - remoteDomain, - _burnToken, - Message.bytes32ToAddress(_mintRecipient), - _amount - ); + ++"address"++ + + The local token address. - return true; - } +## How to Interact with CCTP Contracts - /** - * @notice Add the TokenMessenger for a remote domain. - * @dev Reverts if there is already a TokenMessenger set for domain. - * @param domain Domain of remote TokenMessenger. - * @param tokenMessenger Address of remote TokenMessenger as bytes32. - */ - function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) - external - onlyOwner - { - require(tokenMessenger != bytes32(0), "bytes32(0) not allowed"); +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole CCTP contracts. The primary functionality revolves around the following: - require( - remoteTokenMessengers[domain] == bytes32(0), - "TokenMessenger already set" - ); +- **Sending tokens with a message payload** - initiating a cross-chain transfer of Circle-supported assets along with a message payload to a specific target address on the target chain +- **Receiving tokens with a message payload** - validating messages received from other chains via Wormhole and then minting the tokens for the recipient - remoteTokenMessengers[domain] = tokenMessenger; - emit RemoteTokenMessengerAdded(domain, tokenMessenger); - } +### Sending Tokens and Messages - /** - * @notice Remove the TokenMessenger for a remote domain. - * @dev Reverts if there is no TokenMessenger set for `domain`. - * @param domain Domain of remote TokenMessenger - */ - function removeRemoteTokenMessenger(uint32 domain) external onlyOwner { - // No TokenMessenger set for given remote domain. - require( - remoteTokenMessengers[domain] != bytes32(0), - "No TokenMessenger set" - ); +To initiate a cross-chain transfer, you must call the `transferTokensWithPayload` method of Wormhole's Circle Integration (CCTP) contract. Once you have initiated a transfer, you must fetch the attested Wormhole message and parse the transaction logs to locate a transfer message emitted by the Circle Bridge contract. Then, a request must be sent to Circle's off-chain process with the transfer message to grab the attestation from the process's response, which validates the token mint on the target chain. - bytes32 _removedTokenMessenger = remoteTokenMessengers[domain]; - delete remoteTokenMessengers[domain]; - emit RemoteTokenMessengerRemoved(domain, _removedTokenMessenger); - } +To streamline this process, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank}, which exposes the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank}, including the [`CCTPSender` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. By inheriting this contract, you can transfer USDC while automatically relaying the message payload to the destination chain via a Wormhole-deployed relayer. - /** - * @notice Add minter for the local domain. - * @dev Reverts if a minter is already set for the local domain. - * @param newLocalMinter The address of the minter on the local domain. - */ - function addLocalMinter(address newLocalMinter) external onlyOwner { - require(newLocalMinter != address(0), "Zero address not allowed"); +??? code "CCTP Sender contract" - require( - address(localMinter) == address(0), - "Local minter is already set." - ); + ```solidity + abstract contract CCTPSender is CCTPBase { + uint8 internal constant CONSISTENCY_LEVEL_FINALIZED = 15; - localMinter = ITokenMinter(newLocalMinter); + using CCTPMessageLib for *; - emit LocalMinterAdded(newLocalMinter); - } + mapping(uint16 => uint32) public chainIdToCCTPDomain; /** - * @notice Remove the minter for the local domain. - * @dev Reverts if the minter of the local domain is not set. + * Sets the CCTP Domain corresponding to chain 'chain' to be 'cctpDomain' + * So that transfers of USDC to chain 'chain' use the target CCTP domain 'cctpDomain' + * + * This action can only be performed by 'cctpConfigurationOwner', who is set to be the deployer + * + * Currently, cctp domains are: + * Ethereum: Wormhole chain id 2, cctp domain 0 + * Avalanche: Wormhole chain id 6, cctp domain 1 + * Optimism: Wormhole chain id 24, cctp domain 2 + * Arbitrum: Wormhole chain id 23, cctp domain 3 + * Base: Wormhole chain id 30, cctp domain 6 + * + * These can be set via: + * setCCTPDomain(2, 0); + * setCCTPDomain(6, 1); + * setCCTPDomain(24, 2); + * setCCTPDomain(23, 3); + * setCCTPDomain(30, 6); */ - function removeLocalMinter() external onlyOwner { - address _localMinterAddress = address(localMinter); - require(_localMinterAddress != address(0), "No local minter is set."); + function setCCTPDomain(uint16 chain, uint32 cctpDomain) public { + require( + msg.sender == cctpConfigurationOwner, + "Not allowed to set CCTP Domain" + ); + chainIdToCCTPDomain[chain] = cctpDomain; + } - delete localMinter; - emit LocalMinterRemoved(_localMinterAddress); + function getCCTPDomain(uint16 chain) internal view returns (uint32) { + return chainIdToCCTPDomain[chain]; } - // ============ Internal Utils ============ /** - * @notice Deposits and burns tokens from sender to be minted on destination domain. - * Emits a `DepositForBurn` event. - * @param _amount amount of tokens to burn (must be non-zero) - * @param _destinationDomain destination domain - * @param _mintRecipient address of mint recipient on destination domain - * @param _burnToken address of contract to burn deposited tokens, on local domain - * @param _destinationCaller caller on the destination domain, as bytes32 - * @return nonce unique nonce reserved by message + * transferUSDC wraps common boilerplate for sending tokens to another chain using IWormholeRelayer + * - approves the Circle TokenMessenger contract to spend 'amount' of USDC + * - calls Circle's 'depositForBurnWithCaller' + * - returns key for inclusion in WormholeRelayer `additionalVaas` argument + * + * Note: this requires that only the targetAddress can redeem transfers. + * */ - function _depositForBurn( - uint256 _amount, - uint32 _destinationDomain, - bytes32 _mintRecipient, - address _burnToken, - bytes32 _destinationCaller - ) internal returns (uint64 nonce) { - require(_amount > 0, "Amount must be nonzero"); - require(_mintRecipient != bytes32(0), "Mint recipient must be nonzero"); - bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger( - _destinationDomain + function transferUSDC( + uint256 amount, + uint16 targetChain, + address targetAddress + ) internal returns (MessageKey memory) { + IERC20(USDC).approve(address(circleTokenMessenger), amount); + bytes32 targetAddressBytes32 = addressToBytes32CCTP(targetAddress); + uint64 nonce = circleTokenMessenger.depositForBurnWithCaller( + amount, + getCCTPDomain(targetChain), + targetAddressBytes32, + USDC, + targetAddressBytes32 ); + return + MessageKey( + CCTPMessageLib.CCTP_KEY_TYPE, + abi.encodePacked(getCCTPDomain(wormhole.chainId()), nonce) + ); + } - ITokenMinter _localMinter = _getLocalMinter(); - IMintBurnToken _mintBurnToken = IMintBurnToken(_burnToken); - require( - _mintBurnToken.transferFrom( - msg.sender, - address(_localMinter), - _amount - ), - "Transfer operation failed" - ); - _localMinter.burn(_burnToken, _amount); + // Publishes a CCTP transfer of 'amount' of USDC + // and requests a delivery of the transfer along with 'payload' to 'targetAddress' on 'targetChain' + // + // The second step is done by publishing a wormhole message representing a request + // to call 'receiveWormholeMessages' on the address 'targetAddress' on chain 'targetChain' + // with the payload 'abi.encode(amount, payload)' + // (and we encode the amount so it can be checked on the target chain) + function sendUSDCWithPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + uint256 amount + ) internal returns (uint64 sequence) { + MessageKey[] memory messageKeys = new MessageKey[](1); + messageKeys[0] = transferUSDC(amount, targetChain, targetAddress); - // Format message body - bytes memory _burnMessage = BurnMessage._formatMessage( - messageBodyVersion, - Message.addressToBytes32(_burnToken), - _mintRecipient, - _amount, - Message.addressToBytes32(msg.sender) - ); + bytes memory userPayload = abi.encode(amount, payload); + address defaultDeliveryProvider = wormholeRelayer + .getDefaultDeliveryProvider(); - uint64 _nonceReserved = _sendDepositForBurnMessage( - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller, - _burnMessage + (uint256 cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + receiverValue, + gasLimit ); - emit DepositForBurn( - _nonceReserved, - _burnToken, - _amount, - msg.sender, - _mintRecipient, - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller + sequence = wormholeRelayer.sendToEvm{value: cost}( + targetChain, + targetAddress, + userPayload, + receiverValue, + 0, + gasLimit, + targetChain, + address(0x0), + defaultDeliveryProvider, + messageKeys, + CONSISTENCY_LEVEL_FINALIZED ); - - return _nonceReserved; } - /** - * @notice Sends a BurnMessage through the local message transmitter - * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0), - * or else calls sendMessageWithCaller(). - * @param _destinationDomain destination domain - * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32 - * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0), - * any address can call receiveMessage() on destination domain. - * @param _burnMessage formatted BurnMessage bytes (message body) - * @return nonce unique nonce reserved by message - */ - function _sendDepositForBurnMessage( - uint32 _destinationDomain, - bytes32 _destinationTokenMessenger, - bytes32 _destinationCaller, - bytes memory _burnMessage - ) internal returns (uint64 nonce) { - if (_destinationCaller == bytes32(0)) { - return - localMessageTransmitter.sendMessage( - _destinationDomain, - _destinationTokenMessenger, - _burnMessage - ); - } else { - return - localMessageTransmitter.sendMessageWithCaller( - _destinationDomain, - _destinationTokenMessenger, - _destinationCaller, - _burnMessage - ); - } + function addressToBytes32CCTP(address addr) private pure returns (bytes32) { + return bytes32(uint256(uint160(addr))); } +} + ``` - /** - * @notice Mints tokens to a recipient - * @param _tokenMinter address of TokenMinter contract - * @param _remoteDomain domain where burned tokens originate from - * @param _burnToken address of token burned - * @param _mintRecipient recipient address of minted tokens - * @param _amount amount of minted tokens - */ - function _mintAndWithdraw( - address _tokenMinter, - uint32 _remoteDomain, - bytes32 _burnToken, - address _mintRecipient, - uint256 _amount - ) internal { - ITokenMinter _minter = ITokenMinter(_tokenMinter); - address _mintToken = _minter.mint( - _remoteDomain, - _burnToken, - _mintRecipient, - _amount - ); +The `CCTPSender` abstract contract exposes the `sendUSDCWithPayloadToEvm` function. This function publishes a CCTP transfer of the provided `amount` of USDC and requests that the transfer be delivered along with a `payload` to the specified `targetAddress` on the `targetChain`. - emit MintAndWithdraw(_mintRecipient, _amount, _mintToken); - } +```solidity +function sendUSDCWithPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + uint256 amount +) internal returns (uint64 sequence) +``` - /** - * @notice return the remote TokenMessenger for the given `_domain` if one exists, else revert. - * @param _domain The domain for which to get the remote TokenMessenger - * @return _tokenMessenger The address of the TokenMessenger on `_domain` as bytes32 - */ - function _getRemoteTokenMessenger(uint32 _domain) - internal - view - returns (bytes32) - { - bytes32 _tokenMessenger = remoteTokenMessengers[_domain]; - require(_tokenMessenger != bytes32(0), "No TokenMessenger for domain"); - return _tokenMessenger; - } +??? interface "Parameters" - /** - * @notice return the local minter address if it is set, else revert. - * @return local minter as ITokenMinter. - */ - function _getLocalMinter() internal view returns (ITokenMinter) { - require(address(localMinter) != address(0), "Local minter is not set"); - return localMinter; - } + `targetChain` ++"uint16"++ - /** - * @notice Return true if the given remote domain and TokenMessenger is registered - * on this TokenMessenger. - * @param _domain The remote domain of the message. - * @param _tokenMessenger The address of the TokenMessenger on remote domain. - * @return true if a remote TokenMessenger is registered for `_domain` and `_tokenMessenger`, - * on this TokenMessenger. - */ - function _isRemoteTokenMessenger(uint32 _domain, bytes32 _tokenMessenger) - internal - view - returns (bool) - { - return - _tokenMessenger != bytes32(0) && - remoteTokenMessengers[_domain] == _tokenMessenger; - } + The target chain for the transfer. - /** - * @notice Returns true if the message sender is the local registered MessageTransmitter - * @return true if message sender is the registered local message transmitter - */ - function _isLocalMessageTransmitter() internal view returns (bool) { - return - address(localMessageTransmitter) != address(0) && - msg.sender == address(localMessageTransmitter); - } -} - ``` + --- - This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol){target=\_blank} on GitHub. + `targetAddress` ++"address"++ -The functions provided by the Token Messenger contract are as follows: + The target address for the transfer. -- **`depositForBurn`** - deposits and burns tokens from the sender to be minted on the destination domain. Minted tokens will be transferred to `mintRecipient` + --- - ??? interface "Parameters" + `payload` ++"bytes"++ - `amount` ++"uint256"++ - - The amount of tokens to burn. + Arbitrary payload to be delivered to the target chain via Wormhole. - --- + --- - `destinationDomain` ++"uint32"++ - - The network where the token will be minted after burn. + `gasLimit` ++"uint256"++ - --- + The gas limit with which to call `targetAddress`. - `mintRecipient` ++"bytes32"++ - - Address of mint recipient on destination domain. + --- - --- + `amount` ++"uint256"++ - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. + The amount of USDC to transfer. - ??? interface "Returns" + --- - `_nonce` ++"uint64"++ - - Unique nonce reserved by message. +??? interface "Returns" - ??? interface "Emits" + `sequence` ++"uint64"++ - `DepositForBurn` - event emitted when `depositForBurn` is called. The `destinationCaller` is set to `bytes32(0)` to allow any address to call `receiveMessage` on the destination domain + Sequence number of the published VAA containing the delivery instructions. - ??? child "Event Arguments" +When the `sendUSDCWithPayloadToEvm` function is called, the following series of actions are executed: - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +1. **USDC transfer initiation**: - --- + - The Circle Token Messenger contract is approved to spend the specified amount of USDC. + - The `depositForBurnWithCaller` function of the Token Messenger contract is invoked + - A key is returned, which is to be provided to the Wormhole relayer for message delivery - `burnToken` ++"address"++ - - Address of token burnt on source domain. +2. **Message encoding** - the message `payload` is encoded for transmission via the Wormhole relayer. The encoded value also includes the `amount` so that it can be checked on the target chain +3. **Retrieving delivery provider** - the current default delivery provider's address is retrieved +4. **Cost calculation** - the transfer cost is calculated using the Wormhole relayer's `quoteEVMDeliveryPrice` function +5. **Message dispatch**: - --- + - The `sendToEvm` function of the Wormhole relayer is called with the encoded payload, the delivery provider's address, and the arguments passed to `sendUSDCWithPayloadToEvm` + - The function must be called with `msg.value` set to the previously calculated cost (from step 4) + - This function publishes an instruction for the delivery provider to relay the payload and VAAs specified by the key (from step 1) to the target address on the target chain - `amount` ++"uint256"++ - - The deposit amount. +A simple example implementation is as follows: - --- +```solidity +function sendCrossChainDeposit( + uint16 targetChain, + address targetAddress, + address recipient, + uint256 amount, + uint256, + gasLimit +) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must be quoteCrossChainDeposit(targetChain)" + ); - `depositor` ++"address"++ - - Address where deposit is transferred from. + IERC20(USDC).transferFrom(msg.sender, address(this), amount); - --- + bytes memory payload = abi.encode(recipient); + sendUSDCWithPayloadToEvm( + targetChain, + targetAddress, // address (on targetChain) to send token and payload to + payload, + 0, // receiver value + gasLimit, + amount + ); +} +``` - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +The above example sends a specified amount of USDC and the recipient's address as a payload to a target contract on another chain, ensuring that the correct cost is provided for the cross-chain transfer. - --- +### Receiving Tokens and Messages - `destinationDomain` ++"uint32"++ - - - Destination domain. +To complete the cross-chain transfer, you must invoke the `redeemTokensWithPayload` function on the target Wormhole Circle Integration contract. This function verifies the message's authenticity, decodes the payload, confirms the recipient and sender, checks message delivery, and then calls the `receiveMessage` function of the [Message Transmitter](#message-transmitter-contract) contract. - --- +Using the Wormhole-deployed relayer automatically triggers the `receiveWormholeMessages` function. This function is defined in the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} from the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank} and is implemented within the [`CCTPReceiver` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- +??? code "CCTP Receiver contract" - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. + ```solidity + abstract contract CCTPReceiver is CCTPBase { + function redeemUSDC( + bytes memory cctpMessage + ) internal returns (uint256 amount) { + (bytes memory message, bytes memory signature) = abi.decode( + cctpMessage, + (bytes, bytes) + ); + uint256 beforeBalance = IERC20(USDC).balanceOf(address(this)); + circleMessageTransmitter.receiveMessage(message, signature); + return IERC20(USDC).balanceOf(address(this)) - beforeBalance; + } -- **`depositForBurnWithCaller`** - deposits and burns tokens from the sender to be minted on the destination domain. This method differs from `depositForBurn` in that the mint on the destination domain can only be called by the designated `destinationCaller` address + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable { + // Currently, 'sendUSDCWithPayloadToEVM' only sends one CCTP transfer + // That can be modified if the integrator desires to send multiple CCTP transfers + // in which case the following code would have to be modified to support + // redeeming these multiple transfers and checking that their 'amount's are accurate + require( + additionalMessages.length <= 1, + "CCTP: At most one Message is supported" + ); - ??? interface "Parameters" + uint256 amountUSDCReceived; + if (additionalMessages.length == 1) + amountUSDCReceived = redeemUSDC(additionalMessages[0]); - `amount` ++"uint256"++ - - The amount of tokens to burn. + (uint256 amount, bytes memory userPayload) = abi.decode( + payload, + (uint256, bytes) + ); - --- + // Check that the correct amount was received + // It is important to verify that the 'USDC' sent in by the relayer is the same amount + // that the sender sent in on the source chain + require(amount == amountUSDCReceived, "Wrong amount received"); - `destinationDomain` ++"uint32"++ - - The network where the token will be minted after burn. + receivePayloadAndUSDC( + userPayload, + amountUSDCReceived, + sourceAddress, + sourceChain, + deliveryHash + ); + } - --- + // Implement this function to handle in-bound deliveries that include a CCTP transfer + function receivePayloadAndUSDC( + bytes memory payload, + uint256 amountUSDCReceived, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) internal virtual {} +} + ``` - `mintRecipient` ++"bytes32"++ - - Address of mint recipient on destination domain. +Although you do not need to interact with the `receiveWormholeMessages` function directly, it's important to understand what it does. This function processes cross-chain messages and USDC transfers via Wormhole's Circle (CCTP) Bridge. Here's a summary of what it does: - --- +1. **Validate additional messages** - the function checks that there is at most one CCTP transfer message in the `additionalMessages` array, as it currently only supports processing a single CCTP transfer +2. **Redeem USDC**: + - If there is a CCTP message, it calls the `redeemUSDC` function of the `CCTPReceiver` contract to decode and redeem the USDC + - This results in the call of the `receiveMessage` function of Circle's Message Transmitter contract to redeem the USDC based on the provided message and signature + - The amount of USDC received is calculated by subtracting the contract's previous balance from the current balance after redeeming the USDC +3. **Decode payload** - the incoming payload is decoded, extracting both the expected amount of USDC and a `userPayload` (which could be any additional data) +4. **Verify the amount** - it ensures that the amount of USDC received matches the amount encoded in the payload. If the amounts don't match, the transaction is reverted +5. **Handle the payload and USDC** - after verifying the amounts, `receivePayloadAndUSDC` is called, which is meant to handle the actual logic for processing the received payload and USDC transfer - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. +You'll need to implement the `receivePayloadAndUSDC` function to transfer the USDC and handle the payload as your application needs. A simple example implementation is as follows: - --- +```solidity +function receivePayloadAndUSDC( + bytes memory payload, + uint256 amountUSDCReceived, + bytes32, // sourceAddress + uint16, // sourceChain + bytes32 // deliveryHash +) internal override onlyWormholeRelayer { + address recipient = abi.decode(payload, (address)); - `destinationCaller` ++"bytes32"++ - - Address of the caller on the destination domain who will trigger the mint. + IERC20(USDC).transfer(recipient, amountUSDCReceived); +} +``` - ??? interface "Returns" +## Complete Example - `_nonce` ++"uint64"++ - - Unique nonce reserved by message. +To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. +--- END CONTENT --- - ??? interface "Emits" +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: CCTP Bridge with Wormhole +description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. +categories: Transfer +--- - `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called +# CCTP with Wormhole Overview - ??? child "Event Arguments" +The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +## Key Features - --- +- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. +- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. +- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. +- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. +- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. +- **Gas payment**: Covering destination gas in automated vs. manual transfers. + - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. + - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. - `burnToken` ++"address"++ - - Address of token burnt on source domain. +## How It Works - --- +This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. - `amount` ++"uint256"++ - - The deposit amount. +1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. - --- +2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. - `depositor` ++"address"++ - - Address where deposit is transferred from. +3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. - --- +4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. - --- +```mermaid +sequenceDiagram + participant User as Alice + participant SourceChain as Circle Bridge
    on Ethereum + participant Circle + participant Guardians as Wormhole Guardians + participant Relayer + participant DestinationChain as Circle Bridge
    on Avalanche - `destinationDomain` ++"uint32"++ - - - Destination domain. + User->>SourceChain: Submit transfer
    (100 USDC to Avalanche) + SourceChain->>Circle: Initiate a burn + Circle->>Circle: Burn USDC and provide attestation + SourceChain->>Guardians: Emit Wormhole message (transfer metadata) + Guardians->>Guardians: Sign message and produce VAA + Relayer->>Guardians: Fetch signed VAA + Relayer->>Circle: Fetch Circle burn attestation + Relayer->>DestinationChain: Submit VAA and
    attestation + DestinationChain->>Circle: Verify Circle attestation + Circle->>User: Mint USDC to Alice +``` - --- +!!! note + For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- +## Use Cases - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. +Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: -- **`replaceDepositForBurn`** — replaces a previous `BurnMessage` to modify the mint recipient and/or the destination caller. The replacement message reuses the `_nonce` created by the original message, which allows the original message's sender to update the details without requiring a new deposit +- **USDC Payments Across Chains** + - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. + - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. - ??? interface "Parameters" +- **USDC-Powered Multichain Settlement** + - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. + - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. - `originalMessage` ++"bytes"++ - - The original burn message to be replaced. +## Next Steps - --- +Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: - `originalAttestation` ++"bytes"++ - - The attestation of the original message. +- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. +- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ +--- BEGIN CONTENT --- +--- +title: Complete USDC Transfer Flow +description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +--- - `newDestinationCaller` ++"bytes32"++ - - The new caller on the destination domain, can be the same or updated. +# Complete USDC Transfer Flow - --- +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} - `newMintRecipient` ++"bytes32"++ - - The new recipient for the minted tokens, can be the same or updated. +## Introduction - ??? interface "Returns" +In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. - None. +Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. - ??? interface "Emits" +Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. - `DepositForBurn` - event emitted when `replaceDepositForBurn` is called. Note that the `destinationCaller` will reflect the new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid +In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. - ??? child "Event Arguments" +## Core Concepts - `nonce` ++"uint64"++ - - Unique nonce reserved by message (indexed). +When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: - --- + - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain - `burnToken` ++"address"++ - - Address of token burnt on source domain. - - --- + - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you - `amount` ++"uint256"++ - - The deposit amount. +## Prerequisites - --- +Before you begin, ensure you have the following: - `depositor` ++"address"++ - - Address where deposit is transferred from. + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples + - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees - --- +## Supported Chains - `mintRecipient` ++"bytes32"++ - - Address receiving minted tokens on destination domain. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. - --- +## Project Setup - `destinationDomain` ++"uint32"++ - - - Destination domain. +In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. - --- +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project - `destinationTokenMessenger` ++"bytes32"++ - - Address of `TokenMessenger` on destination domain. - - --- + ```bash + mkdir cctp-circle + cd cctp-circle + npm init -y + ``` - `destinationCaller` ++"bytes32"++ - - Authorized caller of the `receiveMessage` function on the destination domain, if not equal to `bytes32(0)`. If equal to `bytes32(0)`, any address can call `receiveMessage`. +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control -- **`handleReceiveMessage`** - handles an incoming message received by the local `MessageTransmitter` and takes the appropriate action. For a burn message, it mints the associated token to the requested recipient on the local domain. + ```bash + echo ".env" >> .gitignore + ``` - ???+ note +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries - Though this function can only be called by the local `MessageTransmitter`, it is included here as it emits the essential event for minting tokens and withdrawing to send to the recipient. + ```bash + npm install @wormhole-foundation/sdk dotenv + ``` - ??? interface "Parameters" +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project - `remoteDomain` ++"uint32"++ - - The domain where the message originated. + ```bash + touch .env + ``` - --- + Inside the `.env` file, add your private key - `sender` ++"bytes32"++ - - The address of the sender of the message. + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + ``` - --- + !!! note + Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. - `messageBody` ++"bytes"++ - - The bytes making up the body of the message. +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays - ??? interface "Returns" + 1. Create the helpers file - `success` ++"boolean"++ - - Returns `true` if successful, otherwise, it returns `false`. + ```bash + mkdir helpers + touch helpers/helpers.ts + ``` - ??? interface "Emits" + 2. Open the `helpers.ts` file and add the following code - `MintAndWithdraw` - event emitted when tokens are minted + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { config } from 'dotenv'; +config(); - ??? child "Event arguments" +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} - `localMinter` ++"address"++ - - Minter responsible for minting and burning tokens on the local domain. +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} - --- +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; - `remoteDomain` ++"uint32"++ - - The domain where the message originated from. + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } - --- + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` - `burnToken` ++"address"++ - - Address of contract to burn deposited tokens, on local domain. + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file - --- +6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains - `mintRecipient` ++"address"++ - - Recipient address of minted tokens (indexed). + 1. Create the `manual-transfer.ts` file in the `src` directory - --- + ```bash + touch src/manual-transfer.ts + ``` - `amount` ++"uint256"++ - - Amount of minted tokens. + 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files -### Message Transmitter Contract + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; + ``` -The Message Transmitter contract ensures secure messaging across blockchain domains by managing message dispatch and tracking communication with events like `MessageSent` and `MessageReceived`. It uses a unique nonce for each message, which ensures proper validation, verifies attestation signatures, and prevents replay attacks. + - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more + - **`solana`** - this adds support for Solana, a non-EVM chain + - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions -The contract supports flexible delivery options, allowing messages to be sent to a specific `destinationCaller` or broadcast more generally. It also includes domain-specific configurations to manage communication between chains. +## Manual Transfers -Additional features include replacing previously sent messages, setting maximum message body sizes, and verifying that messages are received only once per nonce to maintain network integrity. +In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. -??? code "Message Transmitter contract" - ```solidity - /* - * Copyright (c) 2022, Circle Internet Financial Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -pragma solidity 0.7.6; +This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. -import "@memview-sol/contracts/TypedMemView.sol"; -import "./interfaces/IMessageTransmitter.sol"; -import "./interfaces/IMessageHandler.sol"; -import "./messages/Message.sol"; -import "./roles/Pausable.sol"; -import "./roles/Rescuable.sol"; -import "./roles/Attestable.sol"; +### Set Up the Transfer Environment -/** - * @title MessageTransmitter - * @notice Contract responsible for sending and receiving messages across chains. - */ -contract MessageTransmitter is - IMessageTransmitter, - Pausable, - Rescuable, - Attestable -{ - // ============ Events ============ - /** - * @notice Emitted when a new message is dispatched - * @param message Raw bytes of message - */ - event MessageSent(bytes message); +#### Configure Transfer Details - /** - * @notice Emitted when a new message is received - * @param caller Caller (msg.sender) on destination domain - * @param sourceDomain The source domain this message originated from - * @param nonce The nonce unique to this message - * @param sender The sender of this message - * @param messageBody message body bytes - */ - event MessageReceived( - address indexed caller, - uint32 sourceDomain, - uint64 indexed nonce, - bytes32 sender, - bytes messageBody - ); +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. - /** - * @notice Emitted when max message body size is updated - * @param newMaxMessageBodySize new maximum message body size, in bytes - */ - event MaxMessageBodySizeUpdated(uint256 newMaxMessageBodySize); +1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed - // ============ Libraries ============ - using TypedMemView for bytes; - using TypedMemView for bytes29; - using Message for bytes29; + ```typescript + const wh = await wormhole('Testnet', [evm, solana]); + ``` + + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. - // ============ State Variables ============ - // Domain of chain on which the contract is deployed - uint32 public immutable localDomain; +2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them - // Message Format version - uint32 public immutable version; + ```typescript + const rcvChain = wh.getChain('Sepolia'); + ``` - // Maximum size of message body, in bytes. - // This value is set by owner. - uint256 public maxMessageBodySize; +3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains - // Next available nonce from this source domain - uint64 public nextAvailableNonce; + ```typescript + const destination = await getSigner(rcvChain); + ``` - // Maps a bytes32 hash of (sourceDomain, nonce) -> uint256 (0 if unused, 1 if used) - mapping(bytes32 => uint256) public usedNonces; +4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK - // ============ Constructor ============ - constructor( - uint32 _localDomain, - address _attester, - uint32 _maxMessageBodySize, - uint32 _version - ) Attestable(_attester) { - localDomain = _localDomain; - maxMessageBodySize = _maxMessageBodySize; - version = _version; - } + ```typescript + + ``` - // ============ External Functions ============ - /** - * @notice Send the message to the destination domain and recipient - * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. - * @param destinationDomain Domain of destination chain - * @param recipient Address of message recipient on destination chain as bytes32 - * @param messageBody Raw bytes content of message - * @return nonce reserved by message - */ - function sendMessage( - uint32 destinationDomain, - bytes32 recipient, - bytes calldata messageBody - ) external override whenNotPaused returns (uint64) { - bytes32 _emptyDestinationCaller = bytes32(0); - uint64 _nonce = _reserveAndIncrementNonce(); - bytes32 _messageSender = Message.addressToBytes32(msg.sender); +5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself - _sendMessage( - destinationDomain, - recipient, - _emptyDestinationCaller, - _messageSender, - _nonce, - messageBody - ); + ```typescript + + ``` - return _nonce; - } +#### Initiate the Transfer - /** - * @notice Replace a message with a new message body and/or destination caller. - * @dev The `originalAttestation` must be a valid attestation of `originalMessage`. - * Reverts if msg.sender does not match sender of original message, or if the source domain of the original message - * does not match this MessageTransmitter's local domain. - * @param originalMessage original message to replace - * @param originalAttestation attestation of `originalMessage` - * @param newMessageBody new message body of replaced message - * @param newDestinationCaller the new destination caller, which may be the - * same as the original destination caller, a new destination caller, or an empty - * destination caller (bytes32(0), indicating that any destination caller is valid.) - */ - function replaceMessage( - bytes calldata originalMessage, - bytes calldata originalAttestation, - bytes calldata newMessageBody, - bytes32 newDestinationCaller - ) external override whenNotPaused { - // Validate each signature in the attestation - _verifyAttestationSignatures(originalMessage, originalAttestation); +To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. - bytes29 _originalMsg = originalMessage.ref(0); +1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself - // Validate message format - _originalMsg._validateMessageFormat(); + ```typescript + amt, + source.address, + destination.address, + automatic + ); + ``` - // Validate message sender - bytes32 _sender = _originalMsg._sender(); - require( - msg.sender == Message.bytes32ToAddress(_sender), - "Sender not permitted to use nonce" - ); +2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer - // Validate source domain - uint32 _sourceDomain = _originalMsg._sourceDomain(); - require( - _sourceDomain == localDomain, - "Message not originally sent from this domain" - ); + ```typescript + console.log(`Started Transfer: `, srcTxids); + ``` - uint32 _destinationDomain = _originalMsg._destinationDomain(); - bytes32 _recipient = _originalMsg._recipient(); - uint64 _nonce = _originalMsg._nonce(); +#### Fetch the Circle Attestation (VAA) - _sendMessage( - _destinationDomain, - _recipient, - newDestinationCaller, - _sender, - _nonce, - newMessageBody - ); - } +Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. - /** - * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the - * destination domain. - * @dev Increment nonce, format the message, and emit `MessageSent` event with message information. - * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible - * to broadcast the message on the destination domain. This is an advanced feature, and the standard - * sendMessage() should be preferred for use cases where a specific destination caller is not required. - * @param destinationDomain Domain of destination chain - * @param recipient Address of message recipient on destination domain as bytes32 - * @param destinationCaller caller on the destination domain, as bytes32 - * @param messageBody Raw bytes content of message - * @return nonce reserved by message - */ - function sendMessageWithCaller( - uint32 destinationDomain, - bytes32 recipient, - bytes32 destinationCaller, - bytes calldata messageBody - ) external override whenNotPaused returns (uint64) { - require( - destinationCaller != bytes32(0), - "Destination caller must be nonzero" - ); - uint64 _nonce = _reserveAndIncrementNonce(); - bytes32 _messageSender = Message.addressToBytes32(msg.sender); +1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds - _sendMessage( - destinationDomain, - recipient, - destinationCaller, - _messageSender, - _nonce, - messageBody - ); + ```typescript + + ``` - return _nonce; - } +2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout - /** - * @notice Receive a message. Messages with a given nonce - * can only be broadcast once for a (sourceDomain, destinationDomain) - * pair. The message body of a valid message is passed to the - * specified recipient for further processing. - * - * @dev Attestation format: - * A valid attestation is the concatenated 65-byte signature(s) of exactly - * `thresholdSignature` signatures, in increasing order of attester address. - * ***If the attester addresses recovered from signatures are not in - * increasing order, signature verification will fail.*** - * If incorrect number of signatures or duplicate signatures are supplied, - * signature verification will fail. - * - * Message format: - * Field Bytes Type Index - * version 4 uint32 0 - * sourceDomain 4 uint32 4 - * destinationDomain 4 uint32 8 - * nonce 8 uint64 12 - * sender 32 bytes32 20 - * recipient 32 bytes32 52 - * messageBody dynamic bytes 84 - * @param message Message bytes - * @param attestation Concatenated 65-byte signature(s) of `message`, in increasing order - * of the attester address recovered from signatures. - * @return success bool, true if successful - */ - function receiveMessage(bytes calldata message, bytes calldata attestation) - external - override - whenNotPaused - returns (bool success) - { - // Validate each signature in the attestation - _verifyAttestationSignatures(message, attestation); + ```typescript + console.log(`Got Attestation: `, attestIds); + ``` - bytes29 _msg = message.ref(0); + The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain - // Validate message format - _msg._validateMessageFormat(); +#### Complete the Transfer on the Destination Chain - // Validate domain - require( - _msg._destinationDomain() == localDomain, - "Invalid destination domain" - ); +Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. - // Validate destination caller - if (_msg._destinationCaller() != bytes32(0)) { - require( - _msg._destinationCaller() == - Message.addressToBytes32(msg.sender), - "Invalid caller for message" - ); - } +Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain - // Validate version - require(_msg._version() == version, "Invalid message version"); +```typescript +console.log(`Completed Transfer: `, dstTxids); - // Validate nonce is available - uint32 _sourceDomain = _msg._sourceDomain(); - uint64 _nonce = _msg._nonce(); - bytes32 _sourceAndNonce = _hashSourceAndNonce(_sourceDomain, _nonce); - require(usedNonces[_sourceAndNonce] == 0, "Nonce already used"); - // Mark nonce used - usedNonces[_sourceAndNonce] = 1; + console.log('Circle Transfer status: ', xfer); - // Handle receive message - bytes32 _sender = _msg._sender(); - bytes memory _messageBody = _msg._messageBody().clone(); - require( - IMessageHandler(Message.bytes32ToAddress(_msg._recipient())) - .handleReceiveMessage(_sourceDomain, _sender, _messageBody), - "handleReceiveMessage() failed" - ); + process.exit(0); +``` - // Emit MessageReceived event - emit MessageReceived( - msg.sender, - _sourceDomain, - _nonce, - _sender, - _messageBody - ); - return true; - } +The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed - /** - * @notice Sets the max message body size - * @dev This value should not be reduced without good reason, - * to avoid impacting users who rely on large messages. - * @param newMaxMessageBodySize new max message body size, in bytes - */ - function setMaxMessageBodySize(uint256 newMaxMessageBodySize) - external - onlyOwner - { - maxMessageBodySize = newMaxMessageBodySize; - emit MaxMessageBodySizeUpdated(maxMessageBodySize); - } +You can find the full code for the manual USDC transfer script below: - // ============ Internal Utils ============ - /** - * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0), - * the message can only be received on the destination chain when called by `_destinationCaller`. - * @dev Format the message and emit `MessageSent` event with message information. - * @param _destinationDomain Domain of destination chain - * @param _recipient Address of message recipient on destination domain as bytes32 - * @param _destinationCaller caller on the destination domain, as bytes32 - * @param _sender message sender, as bytes32 - * @param _nonce nonce reserved for message - * @param _messageBody Raw bytes content of message - */ - function _sendMessage( - uint32 _destinationDomain, - bytes32 _recipient, - bytes32 _destinationCaller, - bytes32 _sender, - uint64 _nonce, - bytes calldata _messageBody - ) internal { - // Validate message body length - require( - _messageBody.length <= maxMessageBodySize, - "Message body exceeds max size" - ); +???- code "`manual-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from './helpers/helpers'; - require(_recipient != bytes32(0), "Recipient must be nonzero"); +(async function () { + const wh = await wormhole('Testnet', [evm, solana]); - // serialize message - bytes memory _message = Message._formatMessage( - version, - localDomain, - _destinationDomain, - _nonce, - _sender, - _recipient, - _destinationCaller, - _messageBody - ); + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); - // Emit MessageSent event - emit MessageSent(_message); - } + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - /** - * @notice hashes `_source` and `_nonce`. - * @param _source Domain of chain where the transfer originated - * @param _nonce The unique identifier for the message from source to - destination - * @return hash of source and nonce - */ - function _hashSourceAndNonce(uint32 _source, uint64 _nonce) - internal - pure - returns (bytes32) - { - return keccak256(abi.encodePacked(_source, _nonce)); - } + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000n; - /** - * Reserve and increment next available nonce - * @return nonce reserved - */ - function _reserveAndIncrementNonce() internal returns (uint64) { - uint64 _nonceReserved = nextAvailableNonce; - nextAvailableNonce = nextAvailableNonce + 1; - return _nonceReserved; - } -} - ``` + const automatic = false; - This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol){target=\_blank} on GitHub. + // Create the Circle transfer object + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); -The functions provided by the Message Transmitter contract are as follows: + console.log('Circle Transfer object created:', xfer); -- **`receiveMessage`** — processes and validates an incoming message and its attestation. If valid, it triggers further action based on the message body + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); - ??? interface "Parameters" + // Wait for Circle Attestation (VAA) + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) + console.log('Waiting for Attestation'); + const attestIds = await xfer.fetchAttestation(timeout); + console.log(`Got Attestation: `, attestIds); - `message` ++"bytes"++ - - The message to be processed, including details such as sender, recipient, and message body. + // Complete the transfer on the destination chain (Sepolia) + console.log('Completing Transfer'); + const dstTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, dstTxids); - --- + console.log('Circle Transfer status: ', xfer); - `attestation` ++"bytes"++ - - Concatenated 65-byte signature(s) that attest to the validity of the `message`. + process.exit(0); +})(); + ``` - ??? interface "Returns" +### Run Manual Transfer - `success` ++"boolean"++ - - Returns `true` if successful, otherwise, returns `false`. +To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly - ??? interface "Emits" +```bash +npx ts-node src/manual-transfer.ts +``` - `MessageReceived` - event emitted when a new message is received +This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). - ??? child "Event arguments" +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. - `caller` ++"address"++ - - Caller on destination domain. +### Complete Partial Transfer - --- +In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. - `sourceDomain` ++"uint32"++ - - The source domain this message originated from. +This feature is handy for recovering an incomplete transfer or when debugging. - --- +Here’s how you can complete a partial transfer using just the source chain and transaction hash: - `nonce` ++"uint64"++ - - Nonce unique to this message (indexed). +```typescript +wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); - --- + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); +``` - `sender` ++"bytes32"++ - - Sender of this message. +You will need to provide the below requirements to complete the partial transfer: - --- +- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated +- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup - `messageBody` ++"bytes"++ - - The body of the message. +This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. -- **`sendMessage`** — sends a message to the destination domain and recipient. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event +You can find the full code for the manual USDC transfer script below: - ??? interface "Parameters" +??? code "`partial-transfer.ts`" + ```typescript + import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; - `destinationDomain` ++"uint32"++ - - The target blockchain network where the message is to be sent. +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); - --- + // Grab chain Contexts -- these hold a reference to a cached rpc client + const rcvChain = wh.getChain('Sepolia'); - `recipient` ++"bytes32"++ - - The recipient's address on the destination domain. + // Get signer from local key + const destination = await getSigner(rcvChain); - --- + const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) - `messageBody` ++"bytes"++ - - The raw bytes content of the message. + // Rebuild the transfer from the source txid + const xfer = await CircleTransfer.from( + wh, + { + chain: 'Avalanche', + txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', + }, + timeout + ); - ??? interface "Returns" + const dstTxIds = await xfer.completeTransfer(destination.signer); + console.log('Completed transfer: ', dstTxIds); - `nonce` ++"uint64"++ - - Nonce unique to this message. + console.log('Circle Transfer status: ', xfer); - ??? interface "Emits" + process.exit(0); +})(); + ``` - `MessageSent` - event emitted when a new message is dispatched +## Automatic Transfers -??? child "Event arguments" +The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. - `message` ++"bytes"++ - - The raw bytes of the message. +### Set Up the Transfer Environment -- **`sendMessageWithCaller`** — sends a message to the destination domain and recipient, requiring a specific caller to trigger the message on the target chain. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event +#### Configure Transfer Details - ??? interface "Parameters" +The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you - `destinationDomain` ++"uint32"++ - - The target blockchain network where the message is to be sent. +```typescript - --- +``` - `recipient` ++"bytes32"++ - - The recipient's address on the destination domain. +#### Initiate the Transfer - --- +The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain - `destinationCaller` ++"bytes32"++ - - The caller on the destination domain. +```typescript +amt, + source.address, + destination.address, + automatic + ); +``` - --- +#### Log Transfer Details - `messageBody` ++"bytes"++ - - The raw bytes content of the message. +After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer - ??? interface "Returns" +```typescript +console.log(`Started Transfer: `, srcTxids); - `nonce` ++"uint64"++ - - Nonce unique to this message. + process.exit(0); +``` - ??? interface "Emits" +You can find the full code for the automatic USDC transfer script below: - `MessageSent` - event emitted when a new message is dispatched +??? code "`automatic-transfer.ts`" + ```typescript + import { wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import { getSigner } from '../helpers/helpers'; -??? child "Event arguments" +(async function () { + // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) + const wh = await wormhole('Testnet', [evm, solana]); - `message` ++"bytes"++ - - The raw bytes of the message. + // Set up source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Sepolia'); -- **`replaceMessage`** — replaces an original message with a new message body and/or updates the destination caller. The replacement message reuses the `_nonce` created by the original message + // Configure the signers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - ??? interface "Parameters" + // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) + const amt = 100_000_001n; - `originalMessage` ++"bytes"++ - - The original message to be replaced. + const automatic = true; - --- + // Create the Circle transfer object (USDC-only) + const xfer = await wh.circleTransfer( + amt, + source.address, + destination.address, + automatic + ); - `originalAttestation` ++"bytes"++ - - Attestation verifying the original message. + console.log('Circle Transfer object created:', xfer); - --- + // Initiate the transfer on the source chain (Avalanche) + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); - `newMessageBody` ++"bytes"++ - - The new content for the replaced message. + process.exit(0); +})(); + ``` - --- +### Run Automatic Transfer - `newDestinationCaller` ++"bytes32"++ - - The new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid. +Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: - ??? interface "Returns" +```bash +npx ts-node src/automatic-transfer.ts +``` - None. +The automatic relayer will take care of fetching the attestation and completing the transfer for you. - ??? interface "Emits" +## Resources - `MessageSent` - event emitted when a new message is dispatched +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. -??? child "Event arguments" +## Conclusion - `message` ++"bytes"++ - - The raw bytes of the message. +In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. -### Token Minter Contract +By following these steps, you've learned how to: -The Token Minter contract manages the minting and burning of tokens across different blockchain domains. It maintains a registry that links local tokens to their corresponding remote tokens, ensuring that tokens maintain a 1:1 exchange rate across domains. +- Set up cross-chain transfers for native USDC between supported chains +- Handle both manual and automatic relaying of transactions +- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer +--- END CONTENT --- -The contract restricts minting and burning functions to a designated Token Messenger, which ensures secure and reliable cross-chain operations. When tokens are burned on a remote domain, an equivalent amount is minted on the local domain for a specified recipient, and vice versa. +Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ +--- BEGIN CONTENT --- +--- +title: Routes +description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. +categories: Connect, Transfer +--- -To enhance control and flexibility, the contract includes mechanisms to pause operations, set burn limits, and update the Token Controller, which governs token minting permissions. Additionally, it provides functionality to add or remove the local Token Messenger and retrieve the local token address associated with a remote token. +## Routes Overview {: #routes-overview} -??? code "Token Minter contract" - ```solidity - /* - * Copyright (c) 2022, Circle Internet Financial Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -pragma solidity 0.7.6; +This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. -import "./interfaces/ITokenMinter.sol"; -import "./interfaces/IMintBurnToken.sol"; -import "./roles/Pausable.sol"; -import "./roles/Rescuable.sol"; -import "./roles/TokenController.sol"; -import "./TokenMessenger.sol"; +Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. -/** - * @title TokenMinter - * @notice Token Minter and Burner - * @dev Maintains registry of local mintable tokens and corresponding tokens on remote domains. - * This registry can be used by caller to determine which token on local domain to mint for a - * burned token on a remote domain, and vice versa. - * It is assumed that local and remote tokens are fungible at a constant 1:1 exchange rate. - */ -contract TokenMinter is ITokenMinter, TokenController, Pausable, Rescuable { - // ============ Events ============ - /** - * @notice Emitted when a local TokenMessenger is added - * @param localTokenMessenger address of local TokenMessenger - * @notice Emitted when a local TokenMessenger is added - */ - event LocalTokenMessengerAdded(address localTokenMessenger); +When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. - /** - * @notice Emitted when a local TokenMessenger is removed - * @param localTokenMessenger address of local TokenMessenger - * @notice Emitted when a local TokenMessenger is removed - */ - event LocalTokenMessengerRemoved(address localTokenMessenger); +## Token Bridge Routes {: #token-bridge-routes} - // ============ State Variables ============ - // Local TokenMessenger with permission to call mint and burn on this TokenMinter - address public localTokenMessenger; +The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. - // ============ Modifiers ============ - /** - * @notice Only accept messages from the registered message transmitter on local domain - */ - modifier onlyLocalTokenMessenger() { - require(_isLocalTokenMessenger(), "Caller not local TokenMessenger"); - _; - } +#### Manual Route {: #manual-route} - // ============ Constructor ============ - /** - * @param _tokenController Token controller address - */ - constructor(address _tokenController) { - _setTokenController(_tokenController); - } +The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. - // ============ External Functions ============ - /** - * @notice Mints `amount` of local tokens corresponding to the - * given (`sourceDomain`, `burnToken`) pair, to `to` address. - * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not - * map to a nonzero local token address. This mapping can be queried using - * getLocalToken(). - * @param sourceDomain Source domain where `burnToken` was burned. - * @param burnToken Burned token address as bytes32. - * @param to Address to receive minted tokens, corresponding to `burnToken`, - * on this domain. - * @param amount Amount of tokens to mint. Must be less than or equal - * to the minterAllowance of this TokenMinter for given `_mintToken`. - * @return mintToken token minted. - */ - function mint( - uint32 sourceDomain, - bytes32 burnToken, - address to, - uint256 amount - ) - external - override - whenNotPaused - onlyLocalTokenMessenger - returns (address mintToken) - { - address _mintToken = _getLocalToken(sourceDomain, burnToken); - require(_mintToken != address(0), "Mint token not supported"); - IMintBurnToken _token = IMintBurnToken(_mintToken); +#### Automatic Route {: #automatic-route} - require(_token.mint(to, amount), "Mint operation failed"); - return _mintToken; - } +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. - /** - * @notice Burn tokens owned by this TokenMinter. - * @param burnToken burnable token address. - * @param burnAmount amount of tokens to burn. Must be - * > 0, and <= maximum burn amount per message. - */ - function burn(address burnToken, uint256 burnAmount) - external - override - whenNotPaused - onlyLocalTokenMessenger - onlyWithinBurnLimit(burnToken, burnAmount) - { - IMintBurnToken _token = IMintBurnToken(burnToken); - _token.burn(burnAmount); - } +## CCTP Routes (USDC) {: #cctp-routes-usdc} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. - /** - * @notice Add TokenMessenger for the local domain. Only this TokenMessenger - * has permission to call mint() and burn() on this TokenMinter. - * @dev Reverts if a TokenMessenger is already set for the local domain. - * @param newLocalTokenMessenger The address of the new TokenMessenger on the local domain. - */ - function addLocalTokenMessenger(address newLocalTokenMessenger) - external - onlyOwner - { - require( - newLocalTokenMessenger != address(0), - "Invalid TokenMessenger address" - ); - - require( - localTokenMessenger == address(0), - "Local TokenMessenger already set" - ); +Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. - localTokenMessenger = newLocalTokenMessenger; +#### Manual Route {: #manual-route-cctp} - emit LocalTokenMessengerAdded(localTokenMessenger); - } +This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. - /** - * @notice Remove the TokenMessenger for the local domain. - * @dev Reverts if the TokenMessenger of the local domain is not set. - */ - function removeLocalTokenMessenger() external onlyOwner { - address _localTokenMessengerBeforeRemoval = localTokenMessenger; - require( - _localTokenMessengerBeforeRemoval != address(0), - "No local TokenMessenger is set" - ); +#### Automatic Route {: #automatic-route-cctp} - delete localTokenMessenger; - emit LocalTokenMessengerRemoved(_localTokenMessengerBeforeRemoval); - } +Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. - /** - * @notice Set tokenController to `newTokenController`, and - * emit `SetTokenController` event. - * @dev newTokenController must be nonzero. - * @param newTokenController address of new token controller - */ - function setTokenController(address newTokenController) - external - override - onlyOwner - { - _setTokenController(newTokenController); - } +## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} - /** - * @notice Get the local token address associated with the given - * remote domain and token. - * @param remoteDomain Remote domain - * @param remoteToken Remote token - * @return local token address - */ - function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) - external - view - override - returns (address) - { - return _getLocalToken(remoteDomain, remoteToken); - } +[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. - // ============ Internal Utils ============ - /** - * @notice Returns true if the message sender is the registered local TokenMessenger - * @return True if the message sender is the registered local TokenMessenger - */ - function _isLocalTokenMessenger() internal view returns (bool) { - return - address(localTokenMessenger) != address(0) && - msg.sender == address(localTokenMessenger); - } -} - ``` +#### Manual Route {: #manual-route-ntt} - This contract and the interfaces and contracts it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMinter.sol){target=\_blank} on GitHub. +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. -Most of the methods of the Token Minter contract can be called only by the registered Token Messenger. However, there is one publicly accessible method, a public view function that allows anyone to query the local token associated with a remote domain and token. +#### Automatic Route {: #automatic-route-ntt} -- **`getLocalToken`** — a read-only function that returns the local token address associated with a given remote domain and token +Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. - ??? interface "Parameters" +## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} - `remoteDomain` ++"uint32"++ - - The remote blockchain domain where the token resides. +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). - --- +#### Automatic Route {: #automatic-route-eth} - `remoteToken` ++"bytes32"++ - - The address of the token on the remote domain. +Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. - ??? interface "Returns" +## USDT Bridge Route {: #usdt-bridge-route} - ++"address"++ - - The local token address. +Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. -## How to Interact with CCTP Contracts +#### Automatic Route {: #automatic-route-usdt} -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole CCTP contracts. The primary functionality revolves around the following: +Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. -- **Sending tokens with a message payload** - initiating a cross-chain transfer of Circle-supported assets along with a message payload to a specific target address on the target chain -- **Receiving tokens with a message payload** - validating messages received from other chains via Wormhole and then minting the tokens for the recipient +## tBTC Route {: #tbtc-route} -### Sending Tokens and Messages +You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). -To initiate a cross-chain transfer, you must call the `transferTokensWithPayload` method of Wormhole's Circle Integration (CCTP) contract. Once you have initiated a transfer, you must fetch the attested Wormhole message and parse the transaction logs to locate a transfer message emitted by the Circle Bridge contract. Then, a request must be sent to Circle's off-chain process with the transfer message to grab the attestation from the process's response, which validates the token mint on the target chain. +Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. -To streamline this process, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank}, which exposes the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank}, including the [`CCTPSender` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. By inheriting this contract, you can transfer USDC while automatically relaying the message payload to the destination chain via a Wormhole-deployed relayer. +#### Manual Route {: #manual-route-tbtc} -??? code "CCTP Sender contract" +This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. +--- END CONTENT --- - ```solidity - abstract contract CCTPSender is CCTPBase { - uint8 internal constant CONSISTENCY_LEVEL_FINALIZED = 15; +Doc-Content: https://wormhole.com/docs/products/connect/configuration/configuration-v0/ +--- BEGIN CONTENT --- +--- +title: Configure Your Connect Widget v0 +description: Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. +--- - using CCTPMessageLib for *; +# Configure Your Connect Widget - mapping(uint16 => uint32) public chainIdToCCTPDomain; +## Introduction {: #introduction } - /** - * Sets the CCTP Domain corresponding to chain 'chain' to be 'cctpDomain' - * So that transfers of USDC to chain 'chain' use the target CCTP domain 'cctpDomain' - * - * This action can only be performed by 'cctpConfigurationOwner', who is set to be the deployer - * - * Currently, cctp domains are: - * Ethereum: Wormhole chain id 2, cctp domain 0 - * Avalanche: Wormhole chain id 6, cctp domain 1 - * Optimism: Wormhole chain id 24, cctp domain 2 - * Arbitrum: Wormhole chain id 23, cctp domain 3 - * Base: Wormhole chain id 30, cctp domain 6 - * - * These can be set via: - * setCCTPDomain(2, 0); - * setCCTPDomain(6, 1); - * setCCTPDomain(24, 2); - * setCCTPDomain(23, 3); - * setCCTPDomain(30, 6); - */ - function setCCTPDomain(uint16 chain, uint32 cctpDomain) public { - require( - msg.sender == cctpConfigurationOwner, - "Not allowed to set CCTP Domain" - ); - chainIdToCCTPDomain[chain] = cctpDomain; - } +Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. - function getCCTPDomain(uint16 chain) internal view returns (uint32) { - return chainIdToCCTPDomain[chain]; - } +This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. - /** - * transferUSDC wraps common boilerplate for sending tokens to another chain using IWormholeRelayer - * - approves the Circle TokenMessenger contract to spend 'amount' of USDC - * - calls Circle's 'depositForBurnWithCaller' - * - returns key for inclusion in WormholeRelayer `additionalVaas` argument - * - * Note: this requires that only the targetAddress can redeem transfers. - * - */ +!!! note + For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/products/connect/configuration/data/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. - function transferUSDC( - uint256 amount, - uint16 targetChain, - address targetAddress - ) internal returns (MessageKey memory) { - IERC20(USDC).approve(address(circleTokenMessenger), amount); - bytes32 targetAddressBytes32 = addressToBytes32CCTP(targetAddress); - uint64 nonce = circleTokenMessenger.depositForBurnWithCaller( - amount, - getCCTPDomain(targetChain), - targetAddressBytes32, - USDC, - targetAddressBytes32 - ); - return - MessageKey( - CCTPMessageLib.CCTP_KEY_TYPE, - abi.encodePacked(getCCTPDomain(wormhole.chainId()), nonce) - ); - } +## Get Started - // Publishes a CCTP transfer of 'amount' of USDC - // and requests a delivery of the transfer along with 'payload' to 'targetAddress' on 'targetChain' - // - // The second step is done by publishing a wormhole message representing a request - // to call 'receiveWormholeMessages' on the address 'targetAddress' on chain 'targetChain' - // with the payload 'abi.encode(amount, payload)' - // (and we encode the amount so it can be checked on the target chain) - function sendUSDCWithPayloadToEvm( - uint16 targetChain, - address targetAddress, - bytes memory payload, - uint256 receiverValue, - uint256 gasLimit, - uint256 amount - ) internal returns (uint64 sequence) { - MessageKey[] memory messageKeys = new MessageKey[](1); - messageKeys[0] = transferUSDC(amount, targetChain, targetAddress); +Configure the Wormhole Connect React component by passing a `WormholeConnectConfig` object as the `config` attribute. If using the hosted version, provide `config` and `theme` as JSON-serialized strings on the mount point. - bytes memory userPayload = abi.encode(amount, payload); - address defaultDeliveryProvider = wormholeRelayer - .getDefaultDeliveryProvider(); +=== "React" - (uint256 cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - receiverValue, - gasLimit - ); + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + networks: ['ethereum', 'polygon', 'solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + ethereum: 'https://rpc.ankr.com/eth', + solana: 'https://rpc.ankr.com/solana', + } +} + + + ``` - sequence = wormholeRelayer.sendToEvm{value: cost}( - targetChain, - targetAddress, - userPayload, - receiverValue, - 0, - gasLimit, - targetChain, - address(0x0), - defaultDeliveryProvider, - messageKeys, - CONSISTENCY_LEVEL_FINALIZED - ); - } +=== "HTML Tags" - function addressToBytes32CCTP(address addr) private pure returns (bytes32) { - return bytes32(uint256(uint160(addr))); - } -} + ```html +
    ``` -The `CCTPSender` abstract contract exposes the `sendUSDCWithPayloadToEvm` function. This function publishes a CCTP transfer of the provided `amount` of USDC and requests that the transfer be delivered along with a `payload` to the specified `targetAddress` on the `targetChain`. +## Examples {: #examples } -```solidity -function sendUSDCWithPayloadToEvm( - uint16 targetChain, - address targetAddress, - bytes memory payload, - uint256 receiverValue, - uint256 gasLimit, - uint256 amount -) internal returns (uint64 sequence) -``` +Below are some examples of different ways you can configure Connect. See `WormholeConnectConfig` in the below file for a full view of the supported configuration parameters. -??? interface "Parameters" +??? code "View `WormholeConnectConfig`" + ```ts + import { + ChainName, + WormholeContext, + WormholeConfig, + ChainResourceMap, +} from 'sdklegacy'; +import MAINNET from './mainnet'; +import TESTNET from './testnet'; +import DEVNET from './devnet'; +import type { WormholeConnectConfig } from './types'; +import { + Network, + InternalConfig, + Route, + WrappedTokenAddressCache, +} from './types'; +import { + mergeCustomTokensConfig, + mergeNttGroups, + validateDefaults, +} from './utils'; +import { wrapEventHandler } from './events'; - `targetChain` ++"uint16"++ +import { SDKConverter } from './converter'; - The target chain for the transfer. +import { + wormhole as getWormholeV2, + Wormhole as WormholeV2, + Network as NetworkV2, + Token as TokenV2, + Chain as ChainV2, + ChainTokens as ChainTokensV2, + WormholeConfigOverrides as WormholeConfigOverridesV2, +} from '@wormhole-foundation/sdk'; - --- +import '@wormhole-foundation/sdk/addresses'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import sui from '@wormhole-foundation/sdk/sui'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import algorand from '@wormhole-foundation/sdk/algorand'; - `targetAddress` ++"address"++ +export function buildConfig( + customConfig?: WormholeConnectConfig +): InternalConfig { + const network = ( + customConfig?.network || + customConfig?.env || // TODO remove; deprecated + import.meta.env.REACT_APP_CONNECT_ENV?.toLowerCase() || + 'mainnet' + ).toLowerCase() as Network; - The target address for the transfer. + if (!['mainnet', 'testnet', 'devnet'].includes(network)) + throw new Error(`Invalid env "${network}"`); - --- + const networkData = { MAINNET, DEVNET, TESTNET }[network.toUpperCase()]!; - `payload` ++"bytes"++ + const tokens = mergeCustomTokensConfig( + networkData.tokens, + customConfig?.tokensConfig + ); - Arbitrary payload to be delivered to the target chain via Wormhole. + const sdkConfig = WormholeContext.getConfig(network); - --- + const rpcs = Object.assign( + {}, + sdkConfig.rpcs, + networkData.rpcs, + customConfig?.rpcs + ); - `gasLimit` ++"uint256"++ + const wh = getWormholeContext(network, sdkConfig, rpcs); - The gas limit with which to call `targetAddress`. + if (customConfig?.bridgeDefaults) { + validateDefaults(customConfig.bridgeDefaults, networkData.chains, tokens); + } - --- + const sdkConverter = new SDKConverter(wh); - `amount` ++"uint256"++ + return { + wh, + sdkConfig, + sdkConverter, - The amount of USDC to transfer. + v2Network: sdkConverter.toNetworkV2(network), - --- + network, + isMainnet: network === 'mainnet', + // External resources + rpcs, + rest: Object.assign( + {}, + sdkConfig.rest, + networkData.rest, + customConfig?.rest + ), + graphql: Object.assign({}, networkData.graphql, customConfig?.graphql), + wormholeApi: { + mainnet: 'https://api.wormholescan.io/', + testnet: 'https://api.testnet.wormholescan.io/', + devnet: '', + }[network], + wormholeRpcHosts: { + mainnet: [ + 'https://wormhole-v2-mainnet-api.mcf.rocks', + 'https://wormhole-v2-mainnet-api.chainlayer.network', + 'https://wormhole-v2-mainnet-api.staking.fund', + ], + testnet: [ + 'https://guardian.testnet.xlabs.xyz', + 'https://guardian-01.testnet.xlabs.xyz', + 'https://guardian-02.testnet.xlabs.xyz', + ], + devnet: ['http://localhost:7071'], + }[network], + coinGeckoApiKey: customConfig?.coinGeckoApiKey, -??? interface "Returns" + // Callbacks + triggerEvent: wrapEventHandler(customConfig?.eventHandler), + validateTransfer: customConfig?.validateTransferHandler, - `sequence` ++"uint64"++ + // White lists + chains: networkData.chains, + chainsArr: Object.values(networkData.chains).filter((chain) => { + return customConfig?.networks + ? customConfig.networks!.includes(chain.key) + : true; + }), + tokens, + tokensArr: Object.values(tokens).filter((token) => { + return customConfig?.tokens + ? customConfig.tokens!.includes(token.key) + : true; + }), - Sequence number of the published VAA containing the delivery instructions. + // For token bridge ^_^ + wrappedTokenAddressCache: new WrappedTokenAddressCache( + tokens, + sdkConverter + ), -When the `sendUSDCWithPayloadToEvm` function is called, the following series of actions are executed: + gasEstimates: networkData.gasEstimates, + // TODO: routes that aren't supported yet are disabled + routes: (customConfig?.routes ?? Object.values(Route)).filter((r) => + [ + Route.Bridge, + Route.Relay, + Route.NttManual, + Route.NttRelay, + Route.CCTPManual, + Route.CCTPRelay, + ].includes(r as Route) + ), -1. **USDC transfer initiation**: + // UI details + cta: customConfig?.cta, + explorer: customConfig?.explorer, + attestUrl: { + mainnet: 'https://portalbridge.com/advanced-tools/#/register', + devnet: '', + testnet: + 'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register', + }[network], + bridgeDefaults: customConfig?.bridgeDefaults, + cctpWarning: customConfig?.cctpWarning?.href || '', + pageHeader: customConfig?.pageHeader, + pageSubHeader: customConfig?.pageSubHeader, + menu: customConfig?.menu ?? [], + searchTx: customConfig?.searchTx, + moreTokens: customConfig?.moreTokens, + moreNetworks: customConfig?.moreNetworks, + partnerLogo: customConfig?.partnerLogo, + walletConnectProjectId: + customConfig?.walletConnectProjectId ?? + import.meta.env.REACT_APP_WALLET_CONNECT_PROJECT_ID, + showHamburgerMenu: customConfig?.showHamburgerMenu ?? false, + previewMode: !!customConfig?.previewMode, - - The Circle Token Messenger contract is approved to spend the specified amount of USDC. - - The `depositForBurnWithCaller` function of the Token Messenger contract is invoked - - A key is returned, which is to be provided to the Wormhole relayer for message delivery + // Route options + ethBridgeMaxAmount: customConfig?.ethBridgeMaxAmount ?? 5, + wstETHBridgeMaxAmount: customConfig?.wstETHBridgeMaxAmount ?? 5, -2. **Message encoding** - the message `payload` is encoded for transmission via the Wormhole relayer. The encoded value also includes the `amount` so that it can be checked on the target chain -3. **Retrieving delivery provider** - the current default delivery provider's address is retrieved -4. **Cost calculation** - the transfer cost is calculated using the Wormhole relayer's `quoteEVMDeliveryPrice` function -5. **Message dispatch**: + // NTT config + nttGroups: mergeNttGroups( + tokens, + networkData.nttGroups, + customConfig?.nttGroups + ), - - The `sendToEvm` function of the Wormhole relayer is called with the encoded payload, the delivery provider's address, and the arguments passed to `sendUSDCWithPayloadToEvm` - - The function must be called with `msg.value` set to the previously calculated cost (from step 4) - - This function publishes an instruction for the delivery provider to relay the payload and VAAs specified by the key (from step 1) to the target address on the target chain + // Guardian set + guardianSet: networkData.guardianSet, -A simple example implementation is as follows: + // Render redesign views + useRedesign: customConfig?.useRedesign, + }; +} -```solidity -function sendCrossChainDeposit( - uint16 targetChain, - address targetAddress, - address recipient, - uint256 amount, - uint256, - gasLimit -) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must be quoteCrossChainDeposit(targetChain)" - ); +// Running buildConfig with no argument generates the default configuration +const config = buildConfig(); +export default config; - IERC20(USDC).transferFrom(msg.sender, address(this), amount); +// TODO SDKV2: REMOVE +export function getWormholeContext( + network: Network, + sdkConfig: WormholeConfig, + rpcs: ChainResourceMap +): WormholeContext { + const wh: WormholeContext = new WormholeContext(network, { + ...sdkConfig, + ...{ rpcs }, + }); - bytes memory payload = abi.encode(recipient); - sendUSDCWithPayloadToEvm( - targetChain, - targetAddress, // address (on targetChain) to send token and payload to - payload, - 0, // receiver value - gasLimit, - amount - ); + return wh; } -``` - -The above example sends a specified amount of USDC and the recipient's address as a payload to a target contract on another chain, ensuring that the correct cost is provided for the cross-chain transfer. - -### Receiving Tokens and Messages - -To complete the cross-chain transfer, you must invoke the `redeemTokensWithPayload` function on the target Wormhole Circle Integration contract. This function verifies the message's authenticity, decodes the payload, confirms the recipient and sender, checks message delivery, and then calls the `receiveMessage` function of the [Message Transmitter](#message-transmitter-contract) contract. - -Using the Wormhole-deployed relayer automatically triggers the `receiveWormholeMessages` function. This function is defined in the [`WormholeRelayerSDK.sol` contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayerSDK.sol){target=\_blank} from the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/main){target=\_blank} and is implemented within the [`CCTPReceiver` abstract contract](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/WormholeRelayer/CCTPBase.sol){target=\_blank}. - -??? code "CCTP Receiver contract" - - ```solidity - abstract contract CCTPReceiver is CCTPBase { - function redeemUSDC( - bytes memory cctpMessage - ) internal returns (uint256 amount) { - (bytes memory message, bytes memory signature) = abi.decode( - cctpMessage, - (bytes, bytes) - ); - uint256 beforeBalance = IERC20(USDC).balanceOf(address(this)); - circleMessageTransmitter.receiveMessage(message, signature); - return IERC20(USDC).balanceOf(address(this)) - beforeBalance; - } - - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory additionalMessages, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) external payable { - // Currently, 'sendUSDCWithPayloadToEVM' only sends one CCTP transfer - // That can be modified if the integrator desires to send multiple CCTP transfers - // in which case the following code would have to be modified to support - // redeeming these multiple transfers and checking that their 'amount's are accurate - require( - additionalMessages.length <= 1, - "CCTP: At most one Message is supported" - ); - - uint256 amountUSDCReceived; - if (additionalMessages.length == 1) - amountUSDCReceived = redeemUSDC(additionalMessages[0]); - - (uint256 amount, bytes memory userPayload) = abi.decode( - payload, - (uint256, bytes) - ); - // Check that the correct amount was received - // It is important to verify that the 'USDC' sent in by the relayer is the same amount - // that the sender sent in on the source chain - require(amount == amountUSDCReceived, "Wrong amount received"); +export function getDefaultWormholeContext(network: Network): WormholeContext { + const sdkConfig = WormholeContext.getConfig(network); + const networkData = { mainnet: MAINNET, devnet: DEVNET, testnet: TESTNET }[ + network + ]!; - receivePayloadAndUSDC( - userPayload, - amountUSDCReceived, - sourceAddress, - sourceChain, - deliveryHash - ); - } + const rpcs = Object.assign({}, sdkConfig.rpcs, networkData.rpcs); - // Implement this function to handle in-bound deliveries that include a CCTP transfer - function receivePayloadAndUSDC( - bytes memory payload, - uint256 amountUSDCReceived, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 deliveryHash - ) internal virtual {} + return getWormholeContext(network, sdkConfig, rpcs); } - ``` - -Although you do not need to interact with the `receiveWormholeMessages` function directly, it's important to understand what it does. This function processes cross-chain messages and USDC transfers via Wormhole's Circle (CCTP) Bridge. Here's a summary of what it does: - -1. **Validate additional messages** - the function checks that there is at most one CCTP transfer message in the `additionalMessages` array, as it currently only supports processing a single CCTP transfer -2. **Redeem USDC**: - - If there is a CCTP message, it calls the `redeemUSDC` function of the `CCTPReceiver` contract to decode and redeem the USDC - - This results in the call of the `receiveMessage` function of Circle's Message Transmitter contract to redeem the USDC based on the provided message and signature - - The amount of USDC received is calculated by subtracting the contract's previous balance from the current balance after redeeming the USDC -3. **Decode payload** - the incoming payload is decoded, extracting both the expected amount of USDC and a `userPayload` (which could be any additional data) -4. **Verify the amount** - it ensures that the amount of USDC received matches the amount encoded in the payload. If the amounts don't match, the transaction is reverted -5. **Handle the payload and USDC** - after verifying the amounts, `receivePayloadAndUSDC` is called, which is meant to handle the actual logic for processing the received payload and USDC transfer - -You'll need to implement the `receivePayloadAndUSDC` function to transfer the USDC and handle the payload as your application needs. A simple example implementation is as follows: - -```solidity -function receivePayloadAndUSDC( - bytes memory payload, - uint256 amountUSDCReceived, - bytes32, // sourceAddress - uint16, // sourceChain - bytes32 // deliveryHash -) internal override onlyWormholeRelayer { - address recipient = abi.decode(payload, (address)); - IERC20(USDC).transfer(recipient, amountUSDCReceived); +export async function getWormholeContextV2(): Promise> { + if (config.v2Wormhole) return config.v2Wormhole; + config.v2Wormhole = await newWormholeContextV2(); + return config.v2Wormhole; } -``` - -## Complete Example - -To view a complete example of creating a contract that integrates with Wormhole's CCTP contracts to send and receive USDC cross-chain, check out the [Hello USDC](https://github.com/wormhole-foundation/hello-usdc){target=\_blank} repository on GitHub. ---- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -categories: Connect, Transfer ---- - -# Wormhole Connect - -Wormhole Connect is a customizable widget that brings wrapped and native token cross-chain asset transfers into your dApp in as few as 3 lines of code. Connect is available as a React component or hosted version via CDN so you can easily configure any application to transfer tokens via Wormhole. +export async function newWormholeContextV2(): Promise> { + const v2Config: WormholeConfigOverridesV2 = { chains: {} }; -## Build with Connect + for (const key in config.chains) { + const chainV1 = key as ChainName; + const chainConfigV1 = config.chains[chainV1]!; -[timeline left(wormhole-docs/.snippets/text/build/transfers/connect/connect-timeline.json)] + const chainContextV1 = chainConfigV1.context; -## See It In Action + const chainV2 = config.sdkConverter.toChainV2( + chainV1 as ChainName + ) as ChainV2; -Wormhole Connect is deployed live in several production apps. Here are a few: + const rpc = config.rpcs[chainV1]; + const tokenMap: ChainTokensV2 = {}; -- [Portal Bridge](https://portalbridge.com/){target=\_blank} -- [Jupiter](https://jup.ag/onboard/cctp){target=\_blank} -- [Pancake Swap](https://bridge.pancakeswap.finance/wormhole){target=\_blank} + for (const token of config.tokensArr) { + const nativeChainV2 = config.sdkConverter.toChainV2(token.nativeChain); -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} page to learn how to combine Connect with other Wormhole products, including Native Token Transfer (NTT). + const tokenV2: Partial = { + key: token.key, + chain: chainV2, + symbol: token.symbol, + }; -## Next Steps + if (nativeChainV2 == chainV2) { + const decimals = + token.decimals[chainContextV1] ?? token.decimals.default; + if (!decimals) { + continue; + } else { + tokenV2.decimals = decimals; + } + const address = config.sdkConverter.getNativeTokenAddressV2(token); + if (!address) throw new Error('Token must have address'); + tokenV2.address = address; + } else { + tokenV2.original = nativeChainV2; + if (token.foreignAssets) { + const fa = token.foreignAssets[chainV1]!; -
    + if (!fa) { + continue; + } else { + tokenV2.address = fa.address; + tokenV2.decimals = fa.decimals; + } + } else { + continue; + } + } -- :octicons-tools-16:{ .lg .middle} **Get Started Now** + tokenMap[token.key] = tokenV2 as TokenV2; + } - --- + v2Config.chains![chainV2] = { rpc, tokenMap }; + } - Follow this series of how-to guides to integrate Connect into your React dApp and configure options to fit your user's needs. + return await getWormholeV2( + config.v2Network, + [evm, solana, aptos, cosmwasm, sui, algorand], + v2Config + ); +} - [:custom-arrow: Get started](/docs/build/transfers/connect/overview/#integrate-connect) +// setConfig can be called afterwards to override the default config with integrator-provided config +export function setConfig(customConfig?: WormholeConnectConfig) { + const newConfig: InternalConfig = buildConfig(customConfig); -- :octicons-tools-16:{ .lg .middle } **Multichain Swap** + // We overwrite keys in the existing object so the references to the config + // imported elsewhere point to the new values + for (const key in newConfig) { + /* @ts-ignore */ + config[key] = newConfig[key]; + } +} - --- +// TODO: add config validation step to buildConfig +//validateConfigs(); + + ``` - This tutorial guides you step-by-step through integrating Connect into your React dApp to transfer tokens from Sui to Avalanche Fuji. This tutorial is readily adaptable to work with other [supported networks](/docs/products/reference/supported-networks/){target=\_blank}. +### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints } +Specify supported networks, tokens, and custom RPC endpoints. Your users may encounter rate limits using public RPC endpoints if you don't provide your own. - [:custom-arrow: Get started](/docs/products/connect/tutorials/react-dapp/) +=== "Mainnet" + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -- :octicons-tools-16:{ .lg .middle } **Connect FAQs** +const config: WormholeConnectConfig = { + env: 'mainnet', + networks: ['ethereum', 'polygon', 'solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + ethereum: 'https://rpc.ankr.com/eth', + solana: 'https://rpc.ankr.com/solana', + }, +}; - --- +function App() { + return ; +} + ``` - Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +=== "Testnet" - [:custom-arrow: Visit FAQs](/docs/products/connect/faqs/) + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -- :octicons-tools-16:{ .lg .middle } **Supported Features by Chain** +const config: WormholeConnectConfig = { + env: 'testnet', + networks: ['sepolia', 'arbitrum_sepolia', 'base_sepolia', 'fuji'], - --- + rpcs: { + fuji: 'https://rpc.ankr.com/avalanche_fuji', + base_sepolia: 'https://base-sepolia-rpc.publicnode.com', + }, +}; - Get a more detailed look at Wormhole Connect features with a breakdown of supported features by chain. +function App() { + return ; +} + ``` - [:custom-arrow: Supported Features](/docs/products/connect/reference/support-matrix/) +!!! note + For a complete list of testnet chain names that can be manually added, see the [Testnet Chains List](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/tokenRegistry/src/scripts/importConnect.ts#L44-L55){target=\_blank}. -
    ---- END CONTENT --- +### Fully Customized Theme {: #fully-customized-theme } -Doc-Content: https://wormhole.com/docs/..build/transfers/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Overview -description: Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -categories: Connect, Transfer ---- +Wormhole Connect offers a high level of customizability that suits and integrates with your application's design, including various options for buttons, backgrounds, popovers, fonts, and more. The following example demonstrates a variety of appearance customizations. Remember, if you prefer a visual to aid in designing your widget, you can use the [no code style interface](https://connect-in-style.wormhole.com/){target=\_blank}. -# Wormhole Connect +```jsx +import WormholeConnect, { + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; +import red from '@mui/material/colors/red'; +import lightblue from '@mui/material/colors/lightBlue'; +import grey from '@mui/material/colors/grey'; +import green from '@mui/material/colors/green'; +import orange from '@mui/material/colors/orange'; -## Introduction {: #introduction } - -Wormhole Connect is a React widget that lets developers offer an easy-to-use interface to facilitate cross-chain asset transfers via Wormhole directly in a web application. Check out the [Wormhole Connect GitHub repository](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. - -The [Wormhole TypeScript SDK](https://docs.wormhole.com/wormhole/reference/sdk-docs){target=\_blank} allows you to implement the same functionality as the Connect widget but in your own UI. Check out the docs for more information on using the SDK instead of Connect. - -## Features {: #features } - -Wormhole Connect is easy to customize to suit your application's needs. You can specify technical details like supported assets and custom RPCs or forgo customization and have a full-featured widget. The widget UI is highly customizable, with extensive styling options available, including a user-friendly no code styling interface for those who prefer a more visual approach to design. The features of Wormhole Connect include: - -- Multiple ways to bridge assets ([routes](/docs/products/connect/concepts/routes/){target=\_blank}) -- Extensive ways to style the UI (including the [no code styling interface](https://connect-in-style.wormhole.com/){target=\_blank}) -- Ways to [configure](/docs/products/connect/configuration/data/){target=\_blank} what feature set to offer -- Ability to configure any token to bridge via Wormhole -- [Ability to drop off some gas](/docs/products/connect/reference/support-matrix/){target=\_blank} at the destination - -For more details about the features of Wormhole Connect and a breakdown of supported features by chain, be sure to check [the features page](/docs/products/connect/reference/support-matrix/){target=\_blank}. - -## Integrate Connect {: #integrate-connect } - -### Import Directly into a React App {: #import-directly-into-a-react-app} - -First, install the Wormhole Connect npm package. You can read more about the package by clicking on the following button: [![npm version](https://img.shields.io/npm/v/@wormhole-foundation/wormhole-connect.svg)](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - -```bash -npm i @wormhole-foundation/wormhole-connect -``` - -Now you can import the React component: - -```ts -import WormholeConnect from '@wormhole-foundation/wormhole-connect'; +const customTheme: WormholeConnectTheme = { + mode: 'dark', + primary: grey, + secondary: grey, + divider: 'rgba(255, 255, 255, 0.2)', + background: { + default: '#232323', + }, + text: { + primary: '#ffffff', + secondary: grey[500], + }, + error: red, + info: lightblue, + success: green, + warning: orange, + button: { + primary: 'rgba(255, 255, 255, 0.2)', + primaryText: '#ffffff', + disabled: 'rgba(255, 255, 255, 0.1)', + disabledText: 'rgba(255, 255, 255, 0.4)', + action: orange[300], + actionText: '#000000', + hover: 'rgba(255, 255, 255, 0.7)', + }, + options: { + hover: '#474747', + select: '#5b5b5b', + }, + card: { + background: '#333333', + secondary: '#474747', + elevation: 'none', + }, + popover: { + background: '#1b2033', + secondary: 'rgba(255, 255, 255, 0.5)', + elevation: 'none', + }, + modal: { + background: '#474747', + }, + font: { + primary: 'Impact', + header: 'Impact', + }, +}; -function App() { - return ; +export default function App() { + return ; } ``` -### Use Hosted Version via CDN {: #use-hosted-version-via-cdn} - -If you're not using React, you can still embed Connect on your website by using the hosted version. This uses pre-built packages (which include React) served from NPM by jsdelivr.net. - -```ts title="v1.x" -import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; - -// Existing DOM element where you want to mount Connect -const container = document.getElementById('bridge-container'); - -wormholeConnectHosted(container); -``` +### Environment {: #environment } -For help migrating from Connect v0.x to v1.x, see the [v1 Migration](/docs/products/connect/guides/upgrade/){target=\_blank} guide. +You can configure Connect to be used in Testnet environments, too. You can toggle between Mainnet and Testnet environments by defining the `WormholeConnectConfig` as follows: -???- code "v0.x" - Simply copy and paste the following into your HTML body, and replace the ```INSERT_WORMHOLE_CONNECT_VERSION``` in the links with the most recent production version of Wormhole Connect. You can check what the most recent version is on [NPM](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/latest){target=\_blank}. +=== "Mainnet" - ```html - -
    - - - + ```ts + const config: WormholeConnectConfig = { + env: 'mainnet', + }; ``` - For example, for [0.3.13](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/0.3.13){target=\_blank}: +=== "Testnet" - ```html - -
    - - - + ```ts + const config: WormholeConnectConfig = { + env: 'testnet', + }; ``` +### Custom RPC Endpoint {: #custom-rpc-endpoint } -It is important to periodically update your Wormhole Connect instance to the latest version, as there are frequent functionality and security releases. +You can define a custom RPC provider for your Connect widget to use. This can be especially helpful if you'd like to replace public endpoints with dedicated or private endpoints. -## Configuration {: #configuration} +```ts +const config: WormholeConnectConfig = { + rpcs: { + solana: 'https://rpc.ankr.com/solana/ee827255553bb0fa9e0aaeab27e988707e60ea06ae36be0658b778072e94979e', + }, +}; +``` -This is just an overview of what's possible. Check the [Configuration docs](/docs/products/connect/configuration/data/){target=\_blank} for details about all the configuration options. +### Arbitrary Token {: #arbitrary-token } -The default configuration of Wormhole Connect may not be exactly what you're looking for. You may want to: +The following section shows how to add an arbitrary token to your deployment of Connect. - - Use custom styles - - Restrict the chains that you allow in your app - - Add support for your project's token, and eliminate tokens you don't want to reduce noise - - Configuring custom RPC URLs (This is highly recommended as default public RPCs are heavily throttled) - - Restrict the [routes](/docs/products/connect/concepts/routes/){target=\_blank} that are available +!!! note + You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with Connect. -For additional information on the preceding options, check the [configuration options](/docs/products/connect/configuration/data/){target=\_blank} and customize your widget however you like. ---- END CONTENT --- +This example configuration limits Connect to the Solana and Ethereum networks and a handful of tokens, including `BSKT`, which isn't built in by default and provided under the `tokensConfig` key. -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/installation/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Installation -description: Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -categories: NTT, Transfer ---- +See [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. -# Install the Native Token Transfers CLI +```json +const config: WormholeConnectConfig = { + networks: ['solana', 'ethereum'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC', 'BSKT'], + tokensConfig: { + BSKT: { + key: 'BSKT', + symbol: 'BSKT', + nativeChain: 'solana', + tokenId: { + chain: 'solana', + address: '6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA', + }, + coinGeckoId: 'basket', + icon: 'https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891', + color: '#2894EE', + decimals: { + default: 5, + }, + }, + }, +}; +``` -In this video, the Wormhole team walks you through installing the [Native Token Transfers (NTT) CLI](https://github.com/wormhole-foundation/native-token-transfers/tree/main/cli){target=\_blank}. You’ll see a practical demonstration of running commands, verifying your installation, and addressing common issues that might arise. If you prefer to follow written instructions or want a quick reference for each step, scroll down for the detailed installation guide. +## More Configuration Options {: #more-configuration-options } -To start using the NTT CLI, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. +### Whitelisting Tokens {: #whitelisting-tokens } -
    +By default, Connect will offer its complete built-in list of assets, but you can restrict the displayed assets by defining a subset of tokens under `tokens`. The default full list is as follows: -## Install NTT CLI +| Mainnet | Testnet | +|:--------------:|:----------------------------------:| +| ETH | ETH, ETHsepolia | +| WETH | WETH, WETHsepolia | +| USDCeth | USDCeth | +| WBTC | - | +| USDT | - | +| DAI | - | +| BUSD | - | +| MATIC | MATIC | +| WMATIC | WMATIC | +| USDCpolygon | - | +| BNB | BNB | +| WBNB | WBNB | +| USDCbnb | - | +| AVAX | AVAX | +| WAVAX | WAVAX | +| USDCavax | USDCavax | +| FTM | FTM | +| WFTM | WFTM | +| CELO | CELO | +| GLMR | GLMR | +| WGLMR | WGLMR | +| SOL | WSOL | +| PYTH | - | +| SUI | SUI | +| USDCsol | - | +| APT | APT | +| ETHarbitrum | ETHarbitrum, ETHarbitrum_sepolia | +| WETHarbitrum | WETHarbitrum, WETHarbitrum_sepolia | +| USDCarbitrum | USDCarbitrum | +| ETHoptimism | ETHoptimism, ETHoptimism_sepolia | +| WETHoptimism | WETHoptimism, WETHoptimism_sepolia | +| USDCoptimism | USDCoptimism | +| ETHbase | ETHbase, ETHbase_sepolia | +| WETHbase | WETHbase, WETHbase_sepolia | +| tBTC | tBTC | +| tBTCpolygon | tBTCpolygon | +| tBTCoptimism | tBTCoptimism | +| tBTCarbitrum | tBTCarbitrum | +| tBTCbase | tBTCbase | +| tBTCsol | tBTCsol | +| WETHpolygon | - | +| WETHbsc | - | +| wstETH | wstETH | +| wstETHarbitrum | - | +| wstETHoptimism | - | +| wstETHpolygon | - | +| wstETHbase | - | -The fastest way to deploy Native Token Transfers (NTT) is using the NTT CLI. As prerequisites, ensure you have the following installed: +### Routes {: #routes } -- Install [Bun](https://bun.sh/docs/installation){target=\_blank} +By default, Connect will offer its complete built-in list of routes, but you can restrict the possible route assets by defining a subset under `routes.` By default, Connect will offer its complete built-in list: -Follow these steps to install the NTT CLI: +| Mainnet | Testnet | +|:------------:|:----------:| +| bridge | bridge | +| relay | relay | +| cctpManual | cctpManual | +| cctpRelay | cctpRelay | +| nttManual | nttManual | +| nttRelay | nttRelay | +| ethBridge | - | +| wstETHBridge | - | +| usdtBridge | - | +| tBTC | tBTC | -1. Run the installation command in your terminal: +### Wallet Set Up {: #wallet-connect-project-id } - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` +When using Wormhole Connect, your selected blockchain network determines the available wallet options. -2. Verify the NTT CLI is installed: + - For EVM chains, wallets like MetaMask and WalletConnect are supported + - For Solana, you'll see options such as Phantom, Torus, and Coin98 - ```bash - ntt --version - ``` +The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. -3. Once installed, check out the available [NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} to start using the CLI +If you would like to offer WalletConnect as a supported wallet option, you'll need to obtain a project ID on the [WalletConnect cloud dashboard](https://cloud.walletconnect.com/){target=\_blank}. -## Update NTT CLI +### Toggle Hamburger Menu {: #toggle-hamburger-menu } -To update an existing NTT CLI installation, run the following command in your terminal: +By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, causing the links to be positioned at the bottom. -```bash -ntt update -``` +#### Add Extra Menu Entry {: #add-extra-menu-entry } -NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. +By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): -For local development, you can update your CLI version from a specific branch or install from a local path. +| Property | Description | +|:--------:|:-------------------------------------------:| +| `label` | Link name to show up | +| `href` | Target URL or URN | +| `target` | Anchor standard target, by default `_blank` | +| `order` | Order where the new item should be injected | -To install from a specific branch, run: +#### Sample Configuration {: #sample-configuration } -```bash -ntt update --branch foo +```json +{ + "showHamburgerMenu": false, + "menu": [ + { + "label": "Advance Tools", + "href": "https://portalbridge.com", + "target": "_self", + "order": 1 + } + ] +} ``` -To install locally, run: -```bash -ntt update --path path/to/ntt/repo -``` +### CoinGecko API Key {: #coingecko-api-key } -Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. +The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. -## Where to Go Next +### More Networks {: #more-networks } -
    +Specify a set of extra networks to be displayed on the network selection modal, each linking to a different page, dApp, or mobile app the user will be redirected to. The following properties are accessed through the `moreNetworks` property (e.g., `moreNetworks.href`): +|
    Property
    | Description | +|:--------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `href` | **Required**. Default value for missing network hrefs | +| `target` | Default value for missing network link targets. Defaults to `_self` | +| `description` | Brief description that should be displayed as a tooltip when the user hovers over a more network icon. Used as default for missing network descriptions | +| `networks[].icon` | **Required**. URL data encoded icon to display | +| `networks[].href` | Network href to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | +| `networks[].label` | **Required**. Display text | +| `networks[].name` | Unique network key. Defaults to a snake_case version of the label | +| `networks[].description` | Description value. Defaults to `moreNetworks.description` | +| `networks[].target` | href target value. Defaults to `moreNetworks.target` | +| `networks[].showOpenInNewIcon` | Disable top right open in new icon. Defaults to **true** if target is `_blank` or **false** if target is `_self` | -- :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains** - - --- - - Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +??? code "View full configuration" + ```json + { + ... + "moreNetworks": { + "href": "https://example.com", + "target": "_blank", + "description": "brief description that should be displayed as tooltip when the user hovers over a more network icon", + "networks": [ + { + "icon": "https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891", + "name": "more", + "label": "More networks", + "href": "https://portalbridge.com/#/transfer", + "showOpenInNewIcon": false + } + ] + } + ... +} + ``` - [:custom-arrow: Deploy NTT to EVM chains](/docs/products/native-token-transfers/guides/deploy-to-evm/) +### More Tokens {: #more-tokens } -- :octicons-tools-16:{ .lg .middle } **Deploy to Solana** +Show a particular entry on the select tokens modal, redirecting the user to a different page, dApp, or mobile app. The following properties are accessed through the `moreTokens` property (e.g., `moreTokens.label`): - --- +| Property | Description | +|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `label` | **Required**. Display text | +| `href` | **Required**. URL to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | +| `target` | href target. Defaults to `_self` | - Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +### Explorer {: #explorer } - [:custom-arrow: Deploy NTT to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/) +Enable the explorer button to allow users to search for their transactions on a given explorer, filtering by their wallet address. The following properties are accessed through the `explorer` property (e.g., `explorer.label`): -
    +| Property | Description | +|:--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `label` | Display text. Defaults to `Transactions` | +| `href` | **Required**. URL of the explorer, for instance [https://wormholescan.io/](https://wormholescan.io/){target=\_blank}. If present, the value `address` is replaced with the connected wallet address | +| `target` | `href` target. Defaults to `_blank` | --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/deployment-process/post-deployment/ +Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Post Deployment -description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -categories: NTT, Transfer +title: Connect Data Configuration +description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. +categories: Connect, Transfer --- -# Native Token Transfers Post Deployment +## Data Configuration -To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): +This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. -- Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience -- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure -- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately -- Monitor and maintain your multichain deployment +## Get Started -## Manual Relaying for Solana Transfers +Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. -By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. +=== "React integration" -This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. + ```ts + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -## Where to Go Next +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + } +} -
    + + ``` -- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** +=== "Hosted integration" - --- + ```ts + import WormholeConnect, { + wormholeConnectHosted, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; - [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) +const container = document.getElementById('bridge-container'); -- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** +wormholeConnectHosted(container, { + config, +}); + ``` - --- +!!! note + The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. - Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. +## Examples {: #examples } - [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) +### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } -
    ---- END CONTENT --- +Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers (NTT) -description: This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -categories: NTT, Transfer ---- +=== "Mainnet" -# Native Token Transfers + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Native Token Transfers (NTT) simplifies and enables seamless, flexible token transfers across blockchains. This section provides comprehensive guidance on configuring, deploying, and managing your NTT integration. It includes information relevant to both new token deployments and existing token management. +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Polygon', 'Solana'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, +}; -Visit the [Use Cases](/docs/build/start-building/use-cases/){target=\_blank} and [Product Comparison](/docs/build/start-building/products/){target=\_blank} pages for help determining if NTT will meet the needs of your project. +function App() { + return ; +} + ``` -## Quickstart +=== "Testnet" -If needed, you can generate test tokens for development with the [`example-ntt-token`](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} GitHub repository by following the README instructions. + ```js + import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -The process for creating, deploying, and monitoring NTTs is as follows. Select the title of each step to view the associated guide: +const config: WormholeConnectConfig = { + // You can use Connect with testnet chains by specifying "network": + network: 'Testnet', + chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], + rpcs: { + Avalanche: 'https://rpc.ankr.com/avalanche_fuji', + BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', + }, +}; -[timeline left(wormhole-docs/.snippets/text/build/transfers/ntt/ntt-deployment-process-timeline.json)] +function App() { + return ; +} + ``` -## Deploy NTTs with Launchpad +!!! note + For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. -If you are deploying to EVM blockchains, the [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT. NTT Launchpad replaces manually deploying contracts or configuring relayers for each supported EVM chain. +### Configuring Routes -Follow the [Deploy NTT with Launchpad](/docs/products/native-token-transfers/guides/evm-launchpad/){target=\_blank} guide to create new multichain tokens or integrate existing tokens with just a few clicks. +By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. -## Additional Resources +#### Available Route Plugins -
    +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -- :octicons-gear-16:{ .lg .middle } **NTT CLI Commands** +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route +- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route +- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol - --- +In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. - The NTT CLI tool provides a comprehensive set of commands for creating, configuring, deploying, and monitoring NTTs. This page provides a comprehensive list of available NTT CLI commands, their descriptions, and examples to help you interact effectively with the NTT system. +For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. - [:custom-arrow: NTT CLI Commands](/docs/products/native-token-transfers/reference/cli-commands/) +#### Example: Offer Only CCTP Transfers -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: - --- +```typescript +import WormholeConnect, { + AutomaticCCTPRoute, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], +}; - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +; +``` -
    ---- END CONTENT --- +#### Example: Offer All Default Routes and Third-Party Plugins -Doc-Content: https://wormhole.com/docs/..build/transfers/native-token-transfers/managers-transceivers/ ---- BEGIN CONTENT --- ---- -title: Managers and Transceivers -description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -categories: NTT, Transfer ---- +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -# Managers and Transceivers +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -## Managers +import { myNttConfig } from './consts'; // Custom NTT configuration -_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; -- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain +; +``` - ```solidity - function transfer( - uint256 amount, // amount (in atomic units) - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes32 recipient // recipient address (Wormhole formatted) - ) external payable nonReentrant whenNotPaused returns (uint64) - ``` +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. -- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer +### Adding Custom Tokens {: #custom-tokens } - ```solidity - function quoteDeliveryPrice( - uint16 recipientChain, // chain ID (Wormhole formatted) - bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) - ) public view returns (uint256[] memory, uint256) - ``` +The following section shows how to add an arbitrary token to your deployment of Connect. -- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected +!!! note + You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. - ```solidity - function setPeer( - uint16 peerChainId, // chain ID (Wormhole formatted) - bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) - uint8 decimals, // token decimals on the peer chain - uint256 inboundLimit // inbound rate limit (in atomic units) - ) public onlyOwner - ``` +This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. -## Transceivers +See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. -_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: +```typescript +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system +const config: WormholeConnectConfig = { + tokensConfig: { + BONK: { + key: 'BONK', + symbol: 'BONK', + nativeChain: 'Ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', + }, + coinGeckoId: 'bonk', + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', + }, + }, +}; +``` - ```solidity - function sendMessage( - uint16 recipientChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager - bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) - bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) - ) external payable nonReentrant onlyNttManager - ``` +### Whitelisting Tokens {: #whitelisting-tokens } -- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees +Connect offers a list of built-in tokens by default. You can see it below: - ```solidity - function quoteDeliveryPrice( - uint16 targetChain, // chain ID (Wormhole formatted) - TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) - ) external view returns (uint256) - ``` +- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} +- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} -## Lifecycle of a Message +You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. -### EVM +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -#### Transfer +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Solana'], + tokens: ['ETH', 'SOL', 'BONK'], + rpcs: { + Ethereum: 'https://rpc.ankr.com/eth', + Solana: 'https://rpc.ankr.com/solana', + }, + tokensConfig: { + BONK: { + key: 'BONK', + symbol: 'BONK', + icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', + tokenId: { + chain: 'Ethereum', + address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', + }, + decimals: 18, + }, + }, + wrappedTokens: { + BONK: { + Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', + }, + }, +}; -A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. +function App() { + return ; +} +``` -**Events** +You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. -```ts -/// @notice Emitted when a message is sent from the nttManager. -/// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf -/// @param recipient The recipient of the message. -/// @param amount The amount transferred. -/// @param fee The amount of ether sent along with the tx to cover the delivery fee. -/// @param recipientChain The chain ID of the recipient. -/// @param msgSequence The unique sequence ID of the message. -event TransferSent( - bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence -); -``` +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -#### Rate Limit +const config: WormholeConnectConfig = { + chains: ['Ethereum', 'Solana'], + tokens: [ + // Whitelist BONK on every whitelisted chain + 'BONK', + // Also whitelist USDC, specifically on Solana + ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] + ], + ... +}; -A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. +function App() { + return ; +} +``` -If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. +### User-Inputted Tokens {: #user-inputted-tokens } -Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. +As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). -If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. +If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: -To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -**Events** +const config: WormholeConnectConfig = { + ui: { + disableUserInputtedTokens: true + } +}; -```ts -/// @notice Emitted whenn an outbound transfer is queued. -/// @dev Topic0 -/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. -/// @param queueSequence The location of the transfer in the queue. -event OutboundTransferQueued(uint64 queueSequence); +function App() { + return ; +} ``` -```ts -/// @notice Emitted when an outbound transfer is rate limited. -/// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. -/// @param sender The initial sender of the transfer. -/// @param amount The amount to be transferred. -/// @param currentCapacity The capacity left for transfers within the 24-hour window. -event OutboundTransferRateLimited( - address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity -); -``` +Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. -```ts -/// @notice Emitted when an inbound transfer is queued -/// @dev Topic0 -/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. -/// @param digest The digest of the message. -event InboundTransferQueued(bytes32 digest); -``` +### Transaction Settings {: #transaction-settings } -#### Send +Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. -Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. +const config: WormholeConnectConfig = { + transactionSettings: { + Solana: { + priorityFee: { + // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. + // For example, you can set percentile to 0.95 to make Connect compute the + // 95th percentile priority fee amount based on recent transactions + percentile: 0.95, -**Events** + // Any number, defaults to 1.0. The fee amount is multiplied by this number. + // This can be used to further raise or lower the fees Connect is using. + // For example, percentile=0.95 and percentileMultiple=1.1 would use + // the 95th percentile fee, with a 10% increase + percentileMultiple: 1.1, -```ts -/// @notice Emitted when a message is sent from the transceiver. -/// @dev Topic0 -/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. -/// @param recipientChain The chain ID of the recipient. -/// @param message The message. -event SendTransceiverMessage( - uint16 recipientChain, TransceiverStructs.TransceiverMessage message -); + // Minimum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 1 + min: 200_000, + + // Maximum fee you want to use in microlamports, regardless of recent transactions + // Defaults to 100,000,000 + max: 5_000_000, + } + } + } +}; + +function App() { + return ; +} ``` -#### Receive +!!! note + Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. -Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. +### Wallet Set Up {: #reown-cloud-project-id } -This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. +Your selected blockchain network determines the available wallet options when using Wormhole Connect. -The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. + - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported + - For Solana, you'll see options such as Phantom, Torus, and Coin98 -NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. +The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. -If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. +If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. -**Events** +### CoinGecko API Key {: #coingecko-api-key } -```ts -/// @notice Emitted when a relayed message is received. -/// @dev Topic0 -/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. + +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; + +const config: WormholeConnectConfig = { + coinGeckoApiKey: 'INSERT_API_KEY', +}; + +function App() { + return ; +} ``` +--- END CONTENT --- -```ts -/// @notice Emitted when a message is received. -/// @dev Topic0 -/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. -/// @param digest The digest of the message. -/// @param emitterChainId The chain ID of the emitter. -/// @param emitterAddress The address of the emitter. -/// @param sequence The sequence of the message. -event ReceivedMessage( - bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence -); -``` - -```ts -/// @notice Emitted when a message has already been executed to notify client of against retries. -/// @dev Topic0 -/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. -/// @param sourceNttManager The address of the source nttManager. -/// @param msgHash The keccak-256 hash of the message. -event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); -``` - -#### Mint or Unlock - -Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. - -**Events** - -```ts -/// @notice Emitted when a transfer has been redeemed -/// (either minted or unlocked on the recipient chain). -/// @dev Topic0 -/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. -/// @param digest The digest of the message. -event TransferRedeemed(bytes32 indexed digest); -``` - -### Solana - -#### Transfer - -A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. - -!!! note - Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. - -Depending on the mode and instruction, the following will be produced in the program logs: - -```ts -Program log: Instruction: TransferLock -Program log: Instruction: TransferBurn -``` - -Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. +Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ +--- BEGIN CONTENT --- +--- +title: Connect Theme & UI Customization +description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. +categories: Connect, Transfer +--- -#### Rate Limit +## Theme & UI Customization -During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. +This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. -If the transfer amount fits within the current capacity: +### Changing the Color Scheme -- Reduce the current capacity -- Refill the inbound capacity for the destination chain -- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. +You can customize Connect's color scheme by providing a `theme` prop. -If the transfer amount doesn't fit within the current capacity: +=== "React integration" -- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. -- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error + ```ts + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; -#### Send +const config: WormholeConnectConfig = { + /* Your config... */ +}; -The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', +}; -For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. +function App() { + return ; +} + ``` -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. +=== "Hosted integration" -The following will be produced in the program logs: + ```ts + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; -```ts -Program log: Instruction: ReleaseOutbound -``` +const config: WormholeConnectConfig = { + /* Your config... */ +}; -#### Receive +const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + font: 'Comic Sans; sans-serif', +}; -Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. +const container = document.getElementById('bridge-container'); -The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. +wormholeConnectHosted(container, { + config, + theme, +}); + ``` -The following will be produced in the program logs: +The `WormholeConnectTheme` type supports the following properties: -```ts -Program log: Instruction: ReceiveMessage -``` +|
    Property
    | Description | Example | +|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| +| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | +| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | +| `primary` | Primary color used for buttons | `"#AABBCC"` | +| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | +| `text` | Primary color used for text | `"#AABBCC"` | +| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | +| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | +| `success` | Color to display success messages in | `"#AABBCC"` | +| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | -`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. +### Toggle Hamburger Menu {: #toggle-hamburger-menu } -The following will be produced in the program logs: +By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. -```ts -Program log: Instruction: Redeem -``` +#### Add Extra Menu Entry {: #add-extra-menu-entry } -#### Mint or Unlock +By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): -The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. +| Property | Description | +|:--------:|:-------------------------------------------:| +| `label` | Link name to show up | +| `href` | Target URL or URN | +| `target` | Anchor standard target, by default `_blank` | +| `order` | Order where the new item should be injected | -!!! note - When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. +```jsx +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -Depending on the mode and instruction, the following will be produced in the program logs: +const config: WormholeConnectConfig = { + ui: { + showHamburgerMenu: false, + menu: [ + { + label: 'Advance Tools', + href: 'https://portalbridge.com', + target: '_self', + order: 1, + }, + ], + }, +}; -```ts -Program log: Instruction: ReleaseInboundMint -Program log: Instruction: ReleaseInboundUnlock +function App() { + return ; +} ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..build/transfers/token-bridge/ +Doc-Content: https://wormhole.com/docs/products/connect/faqs/ --- BEGIN CONTENT --- --- -title: Get Started with Token Bridge -description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -categories: Token-Bridge, Transfer +title: Connect FAQs +description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. +categories: Connect, Transfer --- -# Token Bridge - -## Introduction +# Wormhole Connect FAQs -Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. +## What types of assets does Connect support? -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: -## Prerequisites + - Major stablecoins like USDT and USDC (via CCTP) + - Native gas tokens such as ETH, SOL, etc. + - Cross-chain asset swaps through integrators like Mayan -To interact with the Wormhole Token Bridge, you'll need the following: +When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. -- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with -- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers +## What chains does Connect support? -## How to Interact with Token Bridge Contracts +Connect supports around 30 chains, spanning various blockchain runtimes: -The primary functions of the Token Bridge contracts revolve around: + - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) + - Solana + - Move-based chains (Sui, Aptos) -- **Attesting a token** - registering a new token for cross-chain transfers -- **Transferring tokens** - locking and minting tokens across chains -- **Transferring tokens with a payload** - including additional data with transfers +For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. -### Attest a token +## What is gas dropoff? -Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. +Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. -The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. +## Can I customize Connect inside my application? -```solidity -function attestToken( - address tokenAddress, - uint32 nonce -) external payable returns (uint64 sequence); -``` +Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. -??? interface "Parameters" +## Which functions or events does Connect rely on for NTT integration? - `tokenAddress` ++"address"++ - - The contract address of the token to be attested. +Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. - --- +## Do integrators need to enable wallets like Phantom or Backpack in Connect? - `nonce` ++"uint32"++ +Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. - An arbitrary value provided by the caller to ensure uniqueness. +## Which function should be modified to set priority fees for Solana transactions? -??? interface "Returns" +In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. - `sequence` ++"uint64"++ - - A unique identifier for the attestation transaction. +To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. -When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. +The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. -You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. +## Is there a minimum amount for bridging with CCTP or the Connect SDK? -### Transfer Tokens +There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. -Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. +Current relay fees: -Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. - -```solidity -function transferTokens( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint256 arbiterFee, - uint32 nonce -) external payable returns (uint64 sequence); -``` - -??? interface "Parameters" - - `token` ++"address"++ - - The address of the token being transferred. - - --- - - `amount` ++"uint256"++ - The amount of tokens to be transferred. - - --- +- Ethereum L1: ~4.2 USDC +- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. +Additional notes: - --- +- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality +- **Frontend integrations** + - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} + - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. + !!!note + The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/connect/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Connect +description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +categories: Connect, Transfer +--- - `arbiterFee` ++"uint256"++ - Optional fee to be paid to an arbiter for relaying the transfer. +# Get Started with Connect - --- +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} - `nonce` ++"uint32"++ - A unique identifier for the transaction. +## Introduction -??? interface "Returns" +Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. +## Install Connect -Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: -```solidity -function completeTransfer(bytes memory encodedVm) external; +```bash +npm i @wormhole-foundation/wormhole-connect ``` -??? interface "Parameters" +## Prerequisites - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. +Before you begin, make sure you have the following: -!!!note - - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} -### Transfer tokens with payload +- (Optional) To test a transfer from your demo app, you'll need: -While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. + - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} + - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) -Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. +## Install and Set Up Project -```solidity -function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload -) external payable returns (uint64 sequence); -``` +1. Clone the demo repository and navigate to the project directory: -??? interface "Parameters" + ```bash + git clone https://github.com/wormhole-foundation/demo-basic-connect.git + cd demo-basic-connect + ``` - `token` ++"address"++ - - The address of the token being transferred. +2. Install the dependencies: - --- + ```bash + npm install + ``` - `amount` ++"uint256"++ - The amount of tokens to be transferred. +3. Start the application: - --- + ```bash + npm start + ``` - `recipientChain` ++"uint16"++ - The Wormhole chain ID of the destination chain. +4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: - --- + ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) - `recipient` ++"bytes32"++ - The recipient's address on the destination chain. +## Configure Connect - --- +Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: - `nonce` ++"uint32"++ - A unique identifier for the transaction. +```typescript title="App.tsx" +import './App.css'; +import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, +} from '@wormhole-foundation/wormhole-connect'; - --- +function App() { + const config: WormholeConnectConfig = { + // Define the network + network: 'Testnet', - `payload` ++"bytes memory"++ - Arbitrary data payload attached to the transaction. + // Define the chains + chains: ['Sui', 'Avalanche'], -??? interface "Returns" - - `sequence` ++"uint64"++ - - A unique identifier for the transfer transaction. + // UI configuration + ui: { + title: 'SUI Connect TS Demo', + }, + }; -After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. + const theme: WormholeConnectTheme = { + // Define the theme + mode: 'dark', + primary: '#78c4b6', + }; -Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. + return ; +} -```solidity -function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); +export default App; ``` -??? interface "Parameters" - - `encodedVm` ++"bytes memory"++ - - The signed VAA containing the transfer details. - -??? interface "Returns" +The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: - `bytes memory` +- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` +- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains +- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI +- **Defines the theme** - this example sets the mode to `dark` and adds a primary color - The extracted payload data. +## Interact with Connect -## Source Code References +Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. -For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: +## Next Steps -- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} -- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} +Use the following guides to configure your Connect instance: -## Portal Bridge +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. -A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. + --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..learn/glossary/ +Doc-Content: https://wormhole.com/docs/products/connect/guides/hosted-version/ --- BEGIN CONTENT --- --- -title: Glossary -description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -categories: Basics +title: Integrate Connect via CDN +description: +categories: Connect, Transfer --- -# Glossary +# Integrate Connect via CDN -This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. +[Wormhole Connect](/docs/products/connect/overview/){target=\_blank} is a prebuilt UI component that makes it easy to transfer tokens across chains. You can integrate it into any website using either React or a hosted version served via [jsDelivr](https://www.jsdelivr.com/){target=\_blank}. -## Chain ID +This guide focuses on using the hosted version—ideal for simpler setups or non-React environments. It includes everything you need to get started with just a few lines of code. -Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. +If you're using React, refer to the [Get Started with Connect](/docs/products/connect/get-started/){target=\_blank} guide. -You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. +## Install Connect -## Consistency Level +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: -The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. +```bash +npm i @wormhole-foundation/wormhole-connect +``` -## Delivery Provider +## Add Connect to Your Project Using the Hosted Version -A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. +The hosted version uses pre-built packages (including React) served via jsDelivr from npm. To integrate it without using React directly, add the following to your JavaScript project: -## Emitter +```js +import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'bridge-container' not found"); +} -## Finality +wormholeConnectHosted(container); +``` -The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. +You can provide config and theme parameters in a second function argument: -## Guardian +```js +import { + wormholeConnectHosted, +} from '@wormhole-foundation/wormhole-connect'; -A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. +// Existing DOM element where you want to mount Connect +const container = document.getElementById('bridge-container'); +if (!container) { + throw new Error("Element with id 'connect' not found"); +} -## Guardian Network +wormholeConnectHosted(container, { + config: { + rpcs: { + // ... + } + }, + theme: { + background: { + default: '#004547', + } + } +}); +``` -Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. +## Next Steps -## Guardian Set +Use the following guides to configure your Connect instance: -The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +--- END CONTENT --- -## Heartbeat +Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ +--- BEGIN CONTENT --- +--- +title: Wormhole Connect v1.0 Migration Guide +description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. +categories: Connect, Transfer +--- -Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. +# Wormhole Connect v1.0 Migration Guide -You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. +## Overview -## Observation +The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. -An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. +This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: -## Relayer - -A relayer is any process that delivers VAAs to a destination. - -## Sequence + - Update to the latest Connect package + - Apply configuration changes to the **`WormholeConnectConfig`** object + - Understand new routing capabilities and plugin options -A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. +These updates ensure better performance and a smoother integration experience. -## Spy +## Update the Connect Package -A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. +To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. -## VAA +Run the following command in your terminal: -[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. +```bash +npm install @wormhole-foundation/wormhole-connect@^1.0 +``` -## Validator +This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. -A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. ---- END CONTENT --- +## Update the `WormholeConnectConfig` Object -Doc-Content: https://wormhole.com/docs/..learn/governance/overview/ ---- BEGIN CONTENT --- ---- -title: MultiGov Overview -description: Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -categories: MultiGov ---- +In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. -# MultiGov: Cross-Chain Governance with Wormhole +### Summary of Breaking Changes -## Overview +- Chain names are now capitalized: `solana` → `Solana` +- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` +- `networks` renamed to `chains`, with capitalized names +- `routes` updated to use route plugins +- `nttGroups` removed in favor of route plugin configuration +- `tokensConfig` updated, with a new key `wrappedTokens` added +- Many UI-related properties consolidated under a top-level `ui` key +- `customTheme` and `mode` were removed, replaced by a top-level `theme` property -### What Is MultiGov and Why Is It Important? +These changes are explained in more detail below, with examples for easy reference. -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. By leveraging Wormhole's interoperability infrastructure, MultiGov enables seamless voting and proposal mechanisms across various chains. +### Capitalize Chain Names -MultiGov is important because it: +In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. -- **Increases participation** by allowing token holders from multiple chains to engage in governance -- **Enhances security** by leveraging Wormhole's robust cross-chain communication -- **Improves scalability** by integrating any chain supported by Wormhole -- **Enables unified governance** and coordinated decision-making across multiple networks +=== "v0.x" -### Key Features + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + ethereum: 'INSERT_ETH_RPC_URL', + solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` +=== "v1.x" -- **Hub and spoke model** - central coordination on a hub chain with participation from multiple spoke chains. A hub chain is where the governance state lives, while the spoke chains can be considered extensions of governance that allow for participation by token holders on other chains -- **Cross-chain voting** - token holders on any integrated chain can cast votes -- **Vote aggregation** - votes from all chains are collected and tallied on the hub -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Wormhole integration** - secure and reliable cross-chain communication -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain + ```typescript + const config: WormholeConnectConfig = { + rpcs: { + Ethereum: 'INSERT_ETH_RPC_URL', + Solana: 'INSERT_SOLANA_RPC_URL', + }, + }; + ``` -### High-Level Architecture Diagram +You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. -The diagram below represents MultiGov's high-level architecture, focusing on its hub-and-spoke model for decentralized governance across multiple chains. The hub chain acts as the central governance controller, managing proposal creation, vote tallying, and execution, while the spoke chains handle local voting and proposal execution on individual chains. The hub and spoke chains communicate via Wormhole's cross-chain messaging infrastructure, ensuring secure and efficient governance across multiple blockchain networks. +### Rename `env` to `network` -For a deeper understanding of the system's structure and how the components interact, refer to the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\_blank} page. +The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. - -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/multigov-high-level.webp) ---- END CONTENT --- +=== "v0.x" -Doc-Content: https://wormhole.com/docs/..learn/transfers/cctp/ ---- BEGIN CONTENT --- ---- -title: Circle's CCTP Bridge -description: Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -categories: Transfer ---- + ```typescript + const config: WormholeConnectConfig = { + env: 'testnet', + }; + ``` +=== "v1.x" -# Circle's CCTP Bridge + ```typescript + const config: WormholeConnectConfig = { + network: 'Testnet', + }; + ``` -Wormhole Connect and the Wormhole TypeScript SDK support fast, cheap, native USDC bridging between all networks supported by Circle's [Cross-Chain Transfer Protocol](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. CCTP is Circle's native USDC cross-chain transfer attestation service. +If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. -While this protocol is wholly separate from Wormhole itself, Wormhole builds on top of CCTP and adds several valuable augmentations, making it more straightforward to use and more useful for end users. These features include: +```typescript +// Defaults to Mainnet +const config: WormholeConnectConfig = {}; +``` -- **Automated relaying** - eliminates the need for users to redeem USDC transfers themselves -- **Gas payment on the destination chain** - allows users to transfer USDC without needing to pay gas on the destination chain -- **Gas drop off** - enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer +For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. -!!! note - Wormhole supports all CCTP-supported chains but at the moment only a [handful of chains](https://developers.circle.com/stablecoins/docs/supported-domains){target=\_blank} are supported by Circle. +### Rename `networks` to `chains` -You can use Wormhole's CCTP-powered USDC bridging by embedding the [Connect Widget](/docs/products/connect/overview/){target=\_blank} or by integrating the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} directly. +The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. -## Automatic Relaying +=== "v0.x" -To complete a CCTP transfer, the [Circle Attestation](https://developers.circle.com/api-reference/stablecoins/common/get-attestation){target=\_blank} must be delivered to the destination chain. + ```typescript + const config: WormholeConnectConfig = { + networks: ['solana', 'ethereum'], + }; + ``` +=== "v1.x" -This attestation delivery may be difficult or impossible in some contexts. For example, in a browser context, the user doesn't wish to wait for finality to deliver the attestation. To address this difficulty, the Wormhole CCTP relayer may be used either with the [Wormhole Connect Widget](/docs/products/connect/overview/){target=\_blank} or more directly with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}. + ```typescript + const config: WormholeConnectConfig = { + chains: ['Solana', 'Ethereum'], + }; + ``` -The Wormhole CCTP Relayer charges a fee to deliver the attestation and complete the transfer. +### Update `routes` to Use Route Plugins -| Chain | Fee | -|:---------------:|:---------------:| -| Ethereum | 1.0 USDC | -| Everything else | 0.1 USDC | +The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. - +By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: -## Native Gas Drop Off + - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} + - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} -Another advantage of using the automatic relaying feature is the opportunity to transfer some native gas to the receiver on the destination chain. This feature is referred to as _native gas drop off_. +For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. -The ability to perform native gas drop off addresses the common issue where a user may hold a balance of USDC but has no native gas to perform subsequent transactions. +#### Available `route` Plugins - ---- END CONTENT --- +The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -Doc-Content: https://wormhole.com/docs/..learn/transfers/ ---- BEGIN CONTENT --- ---- -title: Multichain Transfers -description: This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -categories: Transfer ---- +???- tip "`route` Plugins" + - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route + - **`CCTPRoute`** - manually redeemed CCTP route + - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route + - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) + - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route + - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route + - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array + - **`MayanRoute`** - route that offers multiple Mayan protocols + - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only + - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only + - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol -# Multichain Transfers +In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. -These sections include information about Wormhole's transfer products to help you learn how they work and determine the best transfer product to fit your needs. +For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. -Use the following links to jump directly to each Wormhole transfer product information page or continue for a product comparison: +Now that you know the available `route` plugins, let's explore some examples of configuring them. -- [**Native Token Transfers (NTT)**](/docs/learn/transfers/native-token-transfers/) - a mechanism to transfer native tokens multichain seamlessly without converting to a wrapped asset -- [**Settlement**](/docs/learn/transfers/settlement/) - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods -- [**Token Bridge**](/docs/learn/transfers/token-bridge/) - a bridging solution that uses a lock and mint mechanism +#### Example: Offer Only CCTP Transfers -## Compare Transfer Products +To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: -A few key comparisons can help you readily differentiate between Wormhole transfer product offerings. Use the following sections to help compare and select products: +```typescript +import WormholeConnect, { + AutomaticCCTPRoute, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -### NTT vs. Token Bridge +const config: WormholeConnectConfig = { + routes: [AutomaticCCTPRoute], +}; -Understand the key differences between Native Token Transfers (NTT) and Token Bridge to determine which solution best fits your needs. +; +``` -- Native Token Transfers (NTT) move tokens in their original form without wrapping them, ensuring compatibility with on-chain applications but requiring custom contracts on both the source and destination chains -- Token Bridge locks tokens on the source chain and mints wrapped versions on the destination chain. This method does not require changes to existing token contracts and supports additional message payloads for more complex use cases +#### Example: Offer All Default Routes and Third-Party Plugins -
    +In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. -| Supports | NTT | Token Bridge | -|---------------------------|--------------------|--------------------| -| Message Payload | :white_check_mark: | :white_check_mark: | -| Wrapped Assets | :x: | :white_check_mark: | -| Native Assets | :white_check_mark: | :x: | -| Contract-Free Development | :x: | :white_check_mark: | -| User-Owned Contracts | :white_check_mark: | :x: | +```typescript +import WormholeConnect, { + DEFAULT_ROUTES, + nttRoutes, + MayanRouteSWIFT, + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -
    +import { myNttConfig } from './consts'; // Custom NTT configuration -In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: +const config: WormholeConnectConfig = { + routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], +}; -
    +; +``` +This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. -### Settlement +### Update the `tokensConfig` Structure -Settlement enables fast and efficient multichain transfers by optimizing liquidity without relying on traditional bridging methods. Unlike NTT, which moves native assets directly between chains, and Token Bridge, which locks tokens and mints wrapped versions, Settlement uses intent-based execution. Users specify the desired transfer outcome, and solvers compete to fulfill it most efficiently. +In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. -By leveraging a decentralized solver network, Settlement ensures efficient cross-chain liquidity without locking assets or requiring asset wrapping, providing a seamless and capital-efficient solution for multichain transactions. +Key Changes to `tokensConfig`: -## Additional Resources + - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK + - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes + - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain -
    +=== "v0.x" -- :octicons-tools-16:{ .lg .middle } **Product Comparison** + In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. - --- + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; - Compare Wormhole's multichain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'ethereum', + icon: Icon.ETH, + tokenId: { + chain: 'ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: { Ethereum: 18, default: 8 }, + foreignAssets: { + Solana: { + address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + decimals: 8, + }, + }, + }, + }, + }; + ``` +=== "v1.x" - [:custom-arrow: Compare Products](/docs/build/start-building/products/#transfer-products) + In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. -- :octicons-book-16:{ .lg .middle } **Use Cases** + ```typescript + import WormholeConnect, { + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; - --- + const config: WormholeConnectConfig = { + tokensConfig: { + WETH: { + key: 'WETH', + symbol: 'WETH', + nativeChain: 'Ethereum', // Chain name now capitalized + icon: Icon.ETH, + tokenId: { + chain: 'Ethereum', + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, + coinGeckoId: 'ethereum', + color: '#62688F', + decimals: 18, // Simplified decimals field + }, + }, + wrappedTokens: { + WETH: { + Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', + /* additional chains */ + }, + }, + }; + ``` - Explore Wormhole's use cases, from multichain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. +### Update NTT Configuration - [:custom-arrow: Discover Use Cases](/docs/build/start-building/use-cases/) +In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +Key changes: -
    ---- END CONTENT --- + - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function + - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/deployment/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers - Deployment Models -description: Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -categories: NTT, Transfer ---- +This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. -# Deployment Models +=== "v0.x" -The Wormhole framework offers two deployment models, each catering to different token management needs: the hub-and-spoke model and the burn-and-mint model. These models provide flexible solutions for both existing token deployments and new projects looking to enable secure and seamless multichain token transfers. + In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. -## Hub-and-Spoke + ```typescript + import WormholeConnect, { + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -The hub-and-spoke model involves locking tokens on a central hub chain and minting them on destination spoke chains. This model maintains the total supply on the hub chain and is backward-compatible with any existing token deployment. + const config: WormholeConnectConfig = { + nttGroups: { + Lido_wstETH: { + nttManagers: [ + { + chainName: 'ethereum', + address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chainName: 'bsc', + address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + tokenKey: 'wstETH', + transceivers: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }, + }; + ``` +=== "v1.x" -This model is ideal for existing token deployments that don't want to alter existing token contracts. It maintains the canonical balance on a hub chain while allowing for secure native deployment to new blockchains. + In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. -- **Hub chain** - tokens are locked when initiating a transfer -- **Spoke chains** - Equivalent tokens are minted on the destination chain + ```typescript + import WormholeConnect, { + nttRoutes, + WormholeConnectConfig, + } from '@wormhole-foundation/wormhole-connect'; -When transferring tokens back to the original hub chain, the tokens on the source spoke chain are burned, and the previously locked tokens on the hub chain are unlocked. However, when transferring tokens directly between spoke chains, the tokens are burned on the source spoke chain and minted on the destination spoke chain. + const config: WormholeConnectConfig = { + routes: [ + ...nttRoutes({ + tokens: { + Lido_wstETH: [ + { + chain: 'Ethereum', + manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', + token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', + transceiver: [ + { + address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', + type: 'wormhole', + }, + ], + }, + { + chain: 'Bsc', + manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', + token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', + transceiver: [ + { + address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', + type: 'wormhole', + }, + ], + }, + ], + }, + }), + /* other routes */ + ], + }; + ``` -## Burn-and-Mint + In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. -The burn-and-mint model involves burning tokens on the source chain and minting them on the destination chain. This results in a simplified multichain transfer process that distributes the total supply across multiple chains and produces a native multichain token. +### Update UI Configuration -This model best suits new token deployments or projects willing to upgrade existing contracts. +In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. -- **Source chain** - tokens are burned when initiating a transfer -- **Destination chain** - equivalent tokens are minted on the destination chain ---- END CONTENT --- +Key UI changes: -Doc-Content: https://wormhole.com/docs/..learn/transfers/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -categories: NTT, Transfer ---- + - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization + - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes -# Native Token Transfers +#### UI Properties -!!!tip "Looking to deploy NTT?" - If you're ready to deploy NTT or access the CLI, follow the detailed [NTT Deployment Section](/docs/build/transfers/native-token-transfers/deployment-process/){target=\_blank}. +The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: - - For deployment steps on EVM, visit the [Deploy to EVM page](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - - For deployment steps on Solana, visit the [Deploy to Solana page](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} + - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions + - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token + - `pageHeader` → `ui.pageHeader` - sets the title and header for the page + - `menu` → `ui.menu` - defines the menu items displayed in the interface + - `searchTx` → `ui.searchTx` - configures the transaction search functionality + - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface + - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI + - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation -## Introduction +Additionally, there are two new properties under `ui`: -Wormhole's Native Token Transfers (NTT) is an open source, flexible, and composable framework for transferring tokens across blockchains. By eliminating wrapped assets, NTT preserves each token’s native properties across chains, letting you maintain complete control over metadata, ownership, upgrade authority, and other custom features. + - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" + - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel -The framework offers two modes of operation for existing token deployments. In locking mode, the original token supply is preserved on a single chain. In contrast, the burning mode enables the deployment of multichain tokens, distributing the supply across various chains. +```typescript +import WormholeConnect, { + WormholeConnectConfig, +} from '@wormhole-foundation/wormhole-connect'; -## Key Features +const config: WormholeConnectConfig = { + ui: { + title: 'My Custom Bridge Example', + getHelpUrl: 'https://examplehelp.com/', + menu: [ + { + label: 'Support', + href: 'https://examplehelp.com/support', + target: '_blank', + order: 1, // Order of appearance in the menu + }, + { + label: 'About', + href: 'https://examplehelp.com/about', + target: '_blank', + order: 2, + }, + ], + showHamburgerMenu: false, + }, +}; +``` -Wormhole's Native Token Transfers (NTT) framework offers a comprehensive and flexible solution for seamless token transfers across blockchains. Below are some of the key features that make this framework stand out: +#### UI Configuration -- **No wrapped tokens** – tokens remain native on every chain where NTT is deployed. All token properties and metadata remain consistent, avoiding any confusion or overhead introduced by wrapped tokens -- **Unified user experience** - tokens retain their properties on each chain, remaining completely fungible and ensuring a consistent user experience -- **No liquidity pools** - transfer tokens without the need for liquidity pools, avoiding fees, slippage, and MEV risk -- **Integrator flexibility** - retained ownership, upgrade authority, and complete customizability over token contracts -- **Advanced rate limiting** - inbound and outbound rate limits are configurable per chain and over arbitrary periods, preventing abuse while managing network congestion and allowing for controlled deployments to new chains -- **Global Accountant** - ensures accounting integrity across chains by checking that the number of tokens burned and transferred out of a chain never exceeds the number of tokens minted -- **Access control** - to prevent unauthorized calls to administrative functions, protocols can choose to assign specific functions, such as the Pauser role, to a separate address from the owner -- **Maximum composability** - open source and extensible for widespread adoption and integration with other protocols -- **Custom attestation** - optionally add external verifiers and configure custom message attestation thresholds +In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. -## Integration Paths +=== "v0.x" -Integrators looking to deploy their token to connected chains can use the NTT framework or the Token Bridge. Both options carry a distinct integration path and feature set depending on your requirements, as outlined in the following sections. + ```typescript + const config: WormholeConnectConfig = { + bridgeDefaults: { + fromNetwork: 'solana', + toNetwork: 'ethereum', + tokenKey: 'USDC', + requiredNetwork: 'solana', + }, + showHamburgerMenu: true, + }; + ``` +=== "v1.x" -### Native Token Transfers Framework + ```typescript + const config: WormholeConnectConfig = { + ui: { + defaultInputs: { + fromChain: 'Solana', // Chain names now capitalized + toChain: 'Ethereum', + tokenKey: 'USDC', + requiredChain: 'Solana', + }, + showHamburgerMenu: true, + }, + }; + ``` -The Native Token Transfers Framework is highly customizable and ideal for applications such as a DeFi governance token deployed across multiple chains, which seeks to achieve fungible multichain liquidity and direct integration into governance processes. +#### Remove `customTheme` and `mode` Properties -- **Mechanism** - can entirely utilize a burn-and-mint mechanism or can be paired for a hub-and-spoke model -- **Security** - fully configurable rate limiting, pausing, access control, and threshold attestations. Integrated with the Global Accountant -- **Contract ownership** - retain ownership and upgrade authority of token contracts on each chain -- **Token contracts** - native contracts owned by your protocol governance -- **Integration** - streamlined, customizable framework allows for more sophisticated and bespoke deployments +In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. -The following example projects demonstrate the use of the Wormhole NTT framework through Wormhole Connect and the TypeScript SDK: +Important details: -- [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\_blank} -- [NTT TS SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\_blank} + - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect + - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes -### Token Bridge +=== "v0.x" -The Token Bridge offers a secure, low-effort integration suitable for applications like a Web3 game that wants to make its token tradable across multiple chains. + ```typescript + const config: WormholeConnectConfig = { + customTheme: { + primaryColor: '#4266f5', + secondaryColor: '#ff5733', + }, + mode: 'dark', + }; -- **Mechanism** - solely utilizes a lock and mint model. Unlike NTT, the Token Bridge issues a wrapped asset on the destination chain, rather than preserving the original token contract -- **Security** - preconfigured rate limiting and integrated Global Accountant -- **Contract ownership** - Token Bridge contracts are upgradeable via [Wormhole Governance](/docs/protocol/security/){target=\_blank} -- **Token contracts** - wrapped asset contract owned by the Wormhole Token Bridge contract, upgradeable via a 13/19 Guardian governance process -- **Integration** - straightforward and permissionless method to deploy on multiple chains + ; + ``` +=== "v1.x" -!!! note - [Learn more](/docs/protocol/infrastructure/vaas/){target=\_blank} about the core messaging primitives in the Wormhole network. + ```typescript + const theme: WormholeConnectTheme = { + mode: 'dark', // Can be dynamically changed + font: 'Arial', + button: { + primary: '#4266f5', + }, + }; -## Supported Token Standards + ; + ``` -Native Token Transfers (NTT) in Wormhole primarily support **ERC-20 tokens**, the most widely used standard for fungible tokens on the Ethereum network and other EVM-compatible blockchains. The NttManager contract leverages the IERC20 interface and SafeERC20 utility from OpenZeppelin to ensure secure and efficient token transfers. Additionally, it supports ERC-20 Burnable tokens, allowing tokens to be burned on the source chain when needed for cross-chain transfers. At this time, NTT focuses on ERC-20 tokens, and other token standards, such as ERC-721 (non-fungible tokens) or ERC-1155 (multi-token standard), are not natively supported. ---- END CONTENT --- +### Removed Configuration Properties -Doc-Content: https://wormhole.com/docs/..learn/transfers/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Overview -description: Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -categories: Settlement, Transfer ---- +Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. -# Wormhole Settlement Overview +Removed config keys: -## Introduction + - `cta` + - `cctpWarning` + - `pageSubHeader` + - `moreTokens` + - `moreChains` + - `ethBridgeMaxAmount` + - `wstETHBridgeMaxAmount` + - `customTheme` + - `mode` -Wormhole Settlement is a fast, institutional-scale digital asset settlement — a new way to transfer assets across chains. +If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. -With Wormhole Settlement, an intent-based asset transfer for individual users and institutions, you can swap, bridge, and build across multiple chains. You can implement cross-chain functionality within your dApps extremely simply and without compromising user experience, widening the horizons of your product offerings and the number and type of users you can cater to. +## Use the CDN-Hosted Version of Wormhole Connect -The Settlement supports Ethereum, Ton, Optimism, Arbitrum, Base, Avalanche, Unichain, Polygon, Solana, and Sui, with many more on the horizon. It is powered by Wormhole Messaging, Wormhole Native Token Transfer (NTT), and Circle's CCTP and built in collaboration with the intent experts at Mayan Finance. +For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. -Settlement represents Wormhole's first step towards optimizing the bridging experience and building a product that users and institutions use daily. Use it to send assets between chains, rebalance institutional inventories on-chain cheaply and quickly, or allow your application to be accessible by any user no matter what assets they hold or what chain they call home. +### Install and Integrate the Hosted Version -## Key Features +1. Install the Connect package via npm: -- **Integrator flexibility** - apps leveraging the SDK can select any one of three potential routes surfaced, each with its tradeoffs concerning time vs cost; they may extend this to users as well -- **Scalable liquidity** - taking into account the sometimes idiosyncratic yet sharp inflows into the Solana ecosystem, the hub-spoke model of the Wormhole Liquidity Layer and the flexible design of Swift are designed for capital efficiency -- **Arbitrary payload support** - integrators can bundle `callData` containing arbitrary protocol actions to enable seamless one-click user experiences, such as swap plus stake + ```bash + npm install @wormhole-foundation/wormhole-connect@^1.0 + ``` -## Integrator Paths +2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: -### SDK Integrators + ```typescript + import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; -Wormhole provides an SDK that enables apps to abstract away the complexity of cross-chain token swaps. The SDK handles route discovery, fee estimation, and transaction construction. Apps can embed this feature in their backend or create an interface for users to bridge into their respective ecosystems quickly. + const container = document.getElementById('connect')!; -### NTT Integrators + wormholeConnectHosted(container); + ``` -NTT partners, current and future, can leverage Wormhole Settlement for near-instant NTT transfers from any chain, including Ethereum mainnet and its L2s. This eliminates waiting for slow source chain confirmation times (sometimes 15 minutes or more). If interested, please [fill out this interest form](https://wormhole.com/contact){target=\_blank}. +### Example: Custom Configuration for Hosted Version -### Chain Integrators +The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: -Due to the hub-spoke model of liquidity, new chains without proven traction can access the same level of liquidity for cross-chain intent fulfillment from day one of mainnet launch as established ecosystems with clear evidence of adoption. +```typescript +import { + wormholeConnectHosted, + MayanRoute, +} from '@wormhole-foundation/wormhole-connect'; -!!!tip - Looking to integrate Wormhole Settlement? If you're ready, check out how to [integrate Wormhole Settlement Routes using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank}. +const container = document.getElementById('connect')!; -## Related Resources +wormholeConnectHosted(container, { + config: { + routes: [MayanRoute], + eventHandler: (e) => { + console.log('Connect event', e); + }, + }, + theme: { + background: { + default: '#004547', + }, + }, +}); +``` -- To learn more about the architecture of Wormhole-native swap protocols, see the [Settlement Protocol Architectures](/docs/products/settlement/concepts/architecture/){target=\_blank} page +In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/..learn/transfers/token-bridge/ +Doc-Content: https://wormhole.com/docs/products/connect/overview/ --- BEGIN CONTENT --- --- -title: Token Bridge -description: Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. -categories: Token-Bridge, Transfer +title: Wormhole Connect +description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. +categories: Connect, Transfer --- -# Token Bridge +# Connect Overview -Transferring tokens across blockchain networks is challenging due to the lack of interoperability. Maintaining token properties such as value, name, and precision while ensuring security during transfers often requires complex and costly solutions like liquidity pools or native swaps, which can introduce inefficiencies and risks. +With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. -Wormhole’s Token Bridge addresses these challenges by providing a decentralized protocol for seamless cross-chain token transfers through a lock-and-mint mechanism. Using Wormhole’s message-passing protocol, the Token Bridge allows standards-compliant tokens, like ERC-20 on Ethereum or SPL on Solana, to be transferred between different blockchains while preserving their original attributes. +## Key Features -Offering a more efficient, scalable, and secure alternative to traditional solutions, the Token Bridge ensures that assets retain their properties across multiple blockchain ecosystems. Additionally, it supports flexible features like [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, enabling custom interactions by allowing tokens to carry additional data for smart contract integration on the destination chain. +Wormhole connect's notable features include: -This page introduces the core concepts and functions of Wormhole’s Token Bridge, explaining how it operates, its key features, and how it enables secure and efficient cross-chain token transfers. +- **In-app multichain transfers**: Bridge assets without leaving your app. +- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. +- **Customizable UI**: Style the bridge interface to match your brand. +- **Optional destination gas**: Provide gas for initial transactions on the target chain. +- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. -### How Does It Work? +Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. -At the core of the Token Bridge lies the lock-and-mint mechanism, which uses the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} with a specific [payload](/docs/protocol/infrastructure/vaas/#token-transfer){target=\_blank} to pass information about the transfer. Tokens on the source chain are locked, and wrapped tokens are minted on the destination chain. This approach guarantees that token transfers are secure and consistent, ensuring that token properties such as name, symbol, and decimal precision are preserved across chains. +## How It Works -Before a token can be transferred to a new chain, the token’s metadata must be [attested](/docs/protocol/infrastructure/vaas/#attestation){target=\_blank}. This process registers the token details (such as decimals and symbol) on the destination chain, enabling the creation of wrapped assets. +When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: -While the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} has no specific receiver by default, transfers sent through the Token Bridge do have a specific receiver chain and address to ensure the tokens are minted to the expected recipient. +1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. +2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). +3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. +6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. +7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. -In addition to standard token transfers, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}. This functionality allows users to attach additional data to token transfers, enabling more complex interactions with smart contracts on the destination chain. For instance, a token transfer can include a payload that triggers specific actions, such as interacting with a decentralized exchange (DEX) or automated market maker (AMM). +!!! tip + If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. -### Token Transfer Flow +## Use Cases -The transfer process is simple yet secure, involving a few key steps: +Here are some key use cases that highlight the power and versatility of Connect: -1. **Attestation** - first, a token's metadata is attested on the source chain, ensuring that its properties are consistent across chains -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - a message detailing the transfer is sent through Wormhole’s Guardian Network, which verifies the transfer and signs the message -4. **Verification and minting** - on the destination chain, the transfer message is verified, and wrapped tokens are minted, or native tokens are released from custody +- **Cross-Chain Swaps and Liquidity Aggregation** -![Token Bridge detailed flow](/docs/images/learn/transfers/token-bridge/token-bridge-diagram.webp) + - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains + - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution -### Key Features of the Token Bridge +- **Cross-Chain Payment Widgets** -The Token Bridge creates wrapped versions when tokens are transferred to a different chain. These wrapped assets represent the locked tokens on the source chain and allow users to interact with them on the destination chain. This mechanism ensures seamless functionality without needing liquidity pools or native token swaps. + - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers -The Token Bridge employs a universal token representation that is compatible with various virtual machine (VM) data types. This allows the tokens to interact with decentralized applications (dApps) across different chains without issues related to differing token standards. +- **Web3 Game Asset Transfers** -### Message and Payload Structure + - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely -To facilitate cross-chain communication, the Token Bridge uses specialized payloads that carry the necessary information for token transfers and attestations. These payloads ensure that the correct tokens are minted or unlocked on the destination chain. +## Next Steps -- `Transfer` - this payload initiates the transfer of tokens, either by minting wrapped tokens or releasing locked tokens -- `TransferWithPayload` - in addition to transferring tokens, this payload carries additional data, allowing integration with smart contracts or dApps on the target chain -- `AssetMeta` - before a token can be transferred for the first time, this payload is used to attest to the token’s metadata, including decimals, symbol, and name -- `RegisterChain` - register the Token Bridge contract (emitter address) for a foreign chain -- `UpgradeContract` - upgrade the contract +Add Connect to your app with these key setup steps: -Each payload type is designed to serve a specific function in the token transfer process, ensuring that the bridge operates efficiently and securely. +[timeline(wormhole-docs/.snippets/text/products/connect/overview/connect-timeline.json)] +--- END CONTENT --- -One of the key challenges in cross-chain token transfers is maintaining the correct token precision. The Token Bridge addresses this using the `AssetMeta` payload to store token metadata. Before transferring a token to a new chain, metadata such as its decimal precision, name, and symbol must be attested. The bridge ensures token amounts are truncated to a maximum of 8 decimals, guaranteeing compatibility with chains that may not support higher decimal precision. For example, an 18-decimal token on Ethereum will be represented with only eight decimals on the destination chain, simplifying integration with various decentralized applications. +Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ +--- BEGIN CONTENT --- +--- +title: Features +description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. +categories: Connect, Transfer +--- -### Security and Authorization +## Feature Support Matrix {: #feature-support-matrix} -The Token Bridge uses an emitter chain and address authorization system to verify the validity of messages. Each Token Bridge endpoint is registered on its respective chain, ensuring only trusted contracts can send or receive transfer messages. +*Scroll down for details about each column.* -The [Wormhole Guardian Network](/docs/protocol/infrastructure/guardians/#guardian-network){target=\_blank} plays a critical role in verifying each transfer and ensuring that the message is signed and relayed securely between chains. +| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | +|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| +| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | +| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | +| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | +| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | +| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | +| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | +| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | +| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | +| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | +| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | +| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | +| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | +| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | +| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | +| Base | ✅ | ✅ | ✅ | ✅ | ✅ | +| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | +| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | +| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | +| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | -### Portal Bridge +## Feature Explanation {: #feature-explanation} -A real-world example of Wormhole's Token Bridge in action is the [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides users with a simple interface to transfer tokens across multiple blockchains. Using the Wormhole infrastructure, Portal Bridge guarantees secure and seamless cross-chain transfers, making it easier for users to move assets between different blockchain ecosystems. ---- END CONTENT --- +### Token Bridge {: #token-bridge} -Doc-Content: https://wormhole.com/docs/ai-resources/ai-resources/ ---- BEGIN CONTENT --- ---- -title: AI Resources -description: Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. ---- +Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. -# AI Resources -Wormhole provides `.txt` files containing the documentation content and navigation structure, optimized for use with large language models (LLMs) and AI tools. These resources help build AI assistants, power code search, or enable custom tooling trained on Wormhole’s docs. +This route appears if both of the following conditions are satisfied: -Each category file includes foundational content from the **Basics** and **Reference** categories to ensure LLMs have the necessary context. + - Both the origin and destination chains support Token Bridge + - No non-Token Bridge routes are available for the selected token -## Download LLM Files +### Token Bridge Relayer {: #token-bridge-relayer} +On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. -| Category | Description | File | Actions | -|----------------|-------------------|-------|----------| -| Index | Navigation index of all Wormhole documentation pages | `llms.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms.txt" } [:octicons-download-16:](/docs/llms.txt){ download="llms.txt" } | -| Full Documentation | Full content of all documentation pages | `llms-full.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-full.txt" } [:octicons-download-16:](/docs/llms-full.txt){ download="llms-full.txt" } | -| Basics | Wormhole's architecture, security, and core components to help understand how the protocol works | `llms-basics.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-basics.txt" } [:octicons-download-16:](/docs/llms-files/llms-basics.txt){ download="llms-basics.txt" } | -| Reference | Reference details such as chain IDs, contract addresses, and finality levels | `llms-reference.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-reference.txt"} [:octicons-download-16:](/docs/llms-files/llms-reference.txt){ download="llms-reference.txt" } | -| NTT | All NTT docs, including architecture, deployment guides, CLI usage, and configuration for EVM and Solana | `llms-ntt.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-ntt.txt" } [:octicons-download-16:](/docs/llms-files/llms-ntt.txt){ download="llms-ntt.txt" } | -| Connect | Setup, features, and configuration details for integrating the Connect widget into your dApp | `llms-connect.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-connect.txt" } [:octicons-download-16:](/docs/llms-files/llms-connect.txt){ download="llms-connect.txt" } | -| Token Bridge | Architecture overview, transfer flows, and smart contract methods for cross-chain token transfers using the Token Bridge | `llms-token-bridge.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-token-bridge.txt" } [:octicons-download-16:](/docs/llms-files/llms-token-bridge.txt){ download="llms-token-bridge.txt" } | -| Settlement | Architecture, integration guides, and setup instructions for building on the Wormhole Settlement protocol | `llms-settlement.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-settlement.txt" } [:octicons-download-16:](/docs/llms-files/llms-settlement.txt){ download="llms-settlement.txt" } | -| Relayers | Guides and reference for using Wormhole’s Relayer module, building cross-chain messaging contracts, and running custom relayers | `llms-relayers.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-relayers.txt" } [:octicons-download-16:](/docs/llms-files/llms-relayers.txt){ download="llms-relayers.txt" } | -| MultiGov | Architecture, deployment steps, and upgrade instructions for multichain governance on EVM and Solana | `llms-multigov.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-multigov.txt" } [:octicons-download-16:](/docs/llms-files/llms-multigov.txt){ download="llms-multigov.txt" } | -| Queries | Guides for using the Wormhole Query SDK and Proxy to construct, test, and verify on-chain data queries across chains | `llms-queries.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-queries.txt" } [:octicons-download-16:](/docs/llms-files/llms-queries.txt){ download="llms-queries.txt" } | -| Solidity SDK | SDK docs for cross-chain messaging, token transfers, relayer integration, and local testing in Solidity | `llms-solidity-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-solidity-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-solidity-sdk.txt){ download="llms-solidity-sdk.txt" } | -| TypeScript SDK | Docs for working with VAAs, payloads, and cross-chain message structures using the TypeScript SDK | `llms-typescript-sdk.txt` | [:octicons-copy-16:](){ .llms action="copy" data-value="llms-typescript-sdk.txt" } [:octicons-download-16:](/docs/llms-files/llms-typescript-sdk.txt){ download="llms-typescript-sdk.txt" } | +Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. -!!! note - The `llms-full.txt` file may exceed the input limits of some language models due to its size. If you encounter limitations, consider using the files by category. ---- END CONTENT --- +This route appears if all of the following conditions are satisfied: -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/concepts/integration/ ---- BEGIN CONTENT --- -TODO +- Both the origin and destination chains support Token Bridge +- Both the origin and destination chains support Token Bridge relayer +- No non-Token Bridge routes are available for the selected token +- The relayer supports the selected token on the origin chain + +### Circle CCTP {: #circle-cctp} + +[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. + +This route appears if all of the following conditions are satisfied: + +- Both the origin and destination chains support Circle CCTP +- The selected token is native Circle-issued USDC + +### ETH Bridge {: #eth-bridge} + +[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. + +This route appears if all of the following conditions are satisfied: + +- Both the origin and destination chains support the ETH Bridge +- The selected token is native ETH, wstETH, or canonical wETH + +### Gas Drop Off {: #gas-drop-off} + +A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. + +This route appears if all of the following conditions are satisfied: + +- Both the origin and destination chains support gas drop off +- An automatic route is selected +- The relayer accepts the selected token to swap into the gas token --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ +Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ --- BEGIN CONTENT --- --- -title: Get Started with CCTP -description: Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. -categories: Transfer +title: Integrate Connect into a React DApp Tutorial +description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. +categories: Connect, Transfer --- -# Get Started with CCTP +# Integrate Connect into a React DApp -## Introduction +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} -[Wormhole CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} enables native USDC transfers between supported chains by burning tokens on the source chain and minting them on the destination. This provides native, canonical USDC movement without the need for wrapped tokens. +## Introduction -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform a manual cross-chain USDC transfer using Circle's CCTP protocol. +In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. -You will initiate the transfer on the source chain, wait for Circle's attestation, and redeem the USDC on the destination chain. +While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. ## Prerequisites -Before you begin, make sure you have the following: +To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. +Before starting this tutorial, ensure you have the following: - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} - - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use +- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} +- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees -This example uses an Avalanche Fuji wallet with [USDC](https://faucet.circle.com/){target=\_blank} and [AVAX](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank}, as well as a Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank}, to pay the transaction fees. You can adapt the steps to work with any [supported EVM chains](/docs/products/reference/supported-networks/#cctp){target=\_blank} that support CCTP. +## Set Up Connect for Sui Transfers -## Configure Your Token Transfer Environment +### Create a React Project -1. Create a new directory and initialize a Node.js project: +Start by setting up your React app: + +1. Open your terminal and run the following command to create a new React app: ```bash - mkdir cctp-bridge - cd cctp-bridge - npm init -y + npx create-react-app connect-tutorial ``` -2. Install the required dependencies: +2. Navigate into the project directory: ```bash - npm install @wormhole-foundation/sdk - npm install -D tsx typescript + cd connect-tutorial ``` -3. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers: +### Install Wormhole Connect - ```bash - touch transfer.ts helper.ts - ``` +Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: -4. Set up secure access to your wallets. This guide assumes you are loading your `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. +```bash +npm install @wormhole-foundation/wormhole-connect +``` - !!! warning - If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. +### Integrate Connect into the Application -## Perform a CCTP Transfer +Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: -This section walks you through a complete manual USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Avalanche Fuji, wait for the Circle attestation, and complete the redemption on Sepolia. +=== "JavaScript" -Start by defining utility functions for signer and token setup: + ```js + import logo from './logo.svg'; + import './App.css'; + import WormholeConnect from '@wormhole-foundation/wormhole-connect'; -1. In `helper.ts`, define functions to load private keys and instantiate EVM signers: + const config = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], + }; - ```ts title="helper.ts" - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, -} from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import evm from '@wormhole-foundation/sdk/evm'; + function App() { + return ; + } -/** - * Returns a signer for the given chain using locally scoped credentials. - * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must - * be loaded securely beforehand, for example via a keystore, secrets - * manager, or environment variables (not recommended). - */ -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; + export default App; + ``` - switch (platform) { - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); - break; - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); - break; - default: - throw new Error(`Unsupported platform: ${platform}`); - } +=== "TypeScript" - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - - ``` - -2. In `transfer.ts`, add the script to perform the manual transfer using CCTP: - - ```ts title="transfer.ts" - import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helper'; - -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm, solana and sui) - const wh = await wormhole('Testnet', [evm, solana, sui]); - - // Grab chain Contexts -- these hold a reference to a cached rpc client - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); - - // Get signer from local key - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); - - // Define the amount of USDC to transfer (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000n; + ```ts + import './App.css'; + import WormholeConnect, { + WormholeConnectConfig, + WormholeConnectTheme, + } from '@wormhole-foundation/wormhole-connect'; - const automatic = false; + function App() { + const config: WormholeConnectConfig = { + network: 'Testnet', + chains: ['Sui', 'Avalanche'], - // Create the circleTransfer transaction (USDC-only) - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); + ui: { + title: 'SUI Connect TS Demo', + }, + }; - const quote = await CircleTransfer.quoteTransfer( - sendChain, - rcvChain, - xfer.transfer - ); - console.log('Quote: ', quote); + const theme: WormholeConnectTheme = { + mode: 'dark', + primary: '#78c4b6', + }; - // Step 1: Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); + return ; + } - // Step 2: Wait for Circle Attestation (VAA) - const timeout = 120 * 1000; // Timeout in milliseconds (120 seconds) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(timeout); - console.log(`Got Attestation: `, attestIds); + export default App; + ``` - // Step 3: Complete the transfer on the destination chain (Sepolia) - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, dstTxids); +- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment +- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche - process.exit(0); -})(); - ``` +### Customize Wormhole Connect -3. Run the script to execute the transfer: +To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. - ```bash - npx tsx transfer.ts - ``` +### Run the Application - You will see terminal output similar to the following: +Make sure you’re in the root directory of your React app, and run the following command to start the application: -
    -npx tsx transfer.ts -Starting Transfer -Started Transfer: - [ '0xdedbf496a1e658efb15bc57f120122b38a3714a560892be7a8c0a7f23c44aca2', - '0x9a8e41837e225edfa62d1913f850c01bd0552e55bf082fd9225df789455a465a' ] - -Waiting for Attestation -Retrying Circle:GetAttestation, attempt 0/60 -Retrying Circle:GetAttestation, attempt 1/60 - -Got Attestation: [{hash: '0x89f8651bf94cfd932ba5bcd2f7795a3fabc6a7c602075fa712c9c55022f5cca8'}] - -Completing Transfer -Completed Transfer: - [ '0x9b81bb30d2a68aa2ecc707a8a1b5af63448223a69b2ead6cf6d172ab880ad0c9'] - -
    +```bash +npm start +``` -To verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. -## Next Steps +## Transfer Tokens from Sui to Fuji -Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: +Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. - - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features ---- END CONTENT --- +To transfer tokens from Sui to Fuji in the Wormhole Connect interface: -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/transfer-usdc/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer +2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network +3. Enter the amount of SUI tokens you wish to transfer -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/overview/ ---- BEGIN CONTENT --- ---- -title: CCTP Bridge with Wormhole -description: Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. -categories: Transfer ---- + ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) -# CCTP with Wormhole Overview +4. Choose to view other routes + + ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) -The integration of [Circle's Cross-Chain Transfer Protocol (CCTP)](https://www.circle.com/cross-chain-transfer-protocol){target=\_blank} with the Wormhole messaging protocol creates a robust system for securely and efficiently transferring native USDC across different blockchain networks while enabling more complex multichain interactions. This combination streamlines the movement of stablecoins, reduces risk, and unlocks new possibilities for decentralized applications. +5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) -## Key Features + !!! note + It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. -- **Secure native USDC transfers**: At its core, CCTP provides a "burn-and-mint" mechanism for transferring native USDC. This eliminates the need for wrapped assets and the associated risks of intermediary bridges. -- **Atomic execution**: By combining CCTP and Wormhole, the transfer of USDC and the execution of accompanying instructions on the destination chain can occur as a single atomic transaction. -- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves. -- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer. -- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer. -- **Gas payment**: Covering destination gas in automated vs. manual transfers. - - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees. - - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion. + ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) -## How It Works +6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain -This section outlines the end-to-end flow for transferring native USDC across chains using CCTP while optionally triggering an action on the destination chain. Circle and Wormhole coordinate each step to ensure a secure, verifiable transfer and execution process. + ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) -1. **Alice initiates a transfer on Ethereum**: She submits a request to the Circle Bridge to send 100 USDC to Avalanche. If desired, she could include optional payload data. +7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet -2. **Tokens are taken into custody and burned**: The Circle Bridge takes custody of Alice's USDC and initiates a burn using Circle's CCTP, triggering an off-chain attestation process. + ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) -3. **A Wormhole message is published**: The transfer metadata is emitted as a Wormhole message. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate and sign it to produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. +Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. -4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche. +## Claim Tokens on Fuji -5. **Tokens are minted**: The Circle Bridge verifies both proofs and mints 100 USDC to Alice using Circle's CCTP. If a payload is included, it can be executed atomically. +After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. -```mermaid -sequenceDiagram - participant User as Alice - participant SourceChain as Circle Bridge
    on Ethereum - participant Circle - participant Guardians as Wormhole Guardians - participant Relayer - participant DestinationChain as Circle Bridge
    on Avalanche +![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) - User->>SourceChain: Submit transfer
    (100 USDC to Avalanche) - SourceChain->>Circle: Initiate a burn - Circle->>Circle: Burn USDC and provide attestation - SourceChain->>Guardians: Emit Wormhole message (transfer metadata) - Guardians->>Guardians: Sign message and produce VAA - Relayer->>Guardians: Fetch signed VAA - Relayer->>Circle: Fetch Circle burn attestation - Relayer->>DestinationChain: Submit VAA and
    attestation - DestinationChain->>Circle: Verify Circle attestation - Circle->>User: Mint USDC to Alice -``` +Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. -!!! note - For a cross-chain transfer to be successful, both the source and destination chains must be among those supported by [Circle's CCTP](https://developers.circle.com/stablecoins/supported-domains){target=\_blank}. +![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) -## Use Cases +## Resources -Integrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include: +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. -- **USDC Payments Across Chains** - - [**CCTP**](/docs/products/cctp-bridge/get-started/): Transfer native USDC using Circle’s burn-and-mint protocol. - - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Automate attestation delivery and gas handling. - - [**Connect**](/docs/products/connect/overview/): Embed multichain USDC transfers directly in your app. +## Conclusion -- **USDC-Powered Multichain Settlement** - - [**Settlement**](/docs/products/settlement/overview/): Use the Liquidity Layer to settle intents with native USDC. - - [**Wormhole TypeScript SDK**](/docs/tools/typescript-sdk/sdk-reference/): Initiate transfers, discover routes, and execute swaps seamlessly. +In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. -## Next Steps +By following these steps, you've learned how to: -Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: +- Set up a React project tailored for cross-chain transfers +- Install and configure Wormhole Connect to support multiple blockchains +- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers +- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks -- [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. -- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. -- [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. +With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/ +Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ --- BEGIN CONTENT --- --- -title: Complete USDC Transfer Flow -description: Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. +title: Get Started with Messaging +description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. +categories: Basics, Typescript-SDK --- -# Complete USDC Transfer Flow - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank} +# Get Started with Messaging -## Introduction +Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. -In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. +## Prerequisites -Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. +Before you begin, ensure you have the following: -Wormhole’s TypeScript SDK simplifies this process by offering automated transfer relaying and handling gas payments on the destination chain. It also offers an option to include native gas tokens for seamless execution. This reduces developer overhead, makes transfers faster and more reliable, and enhances the user experience. +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed +- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed +- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) +- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network +- A private key for signing blockchain transactions -In this guide, we’ll first explore the theory behind CCTP and then provide a step-by-step tutorial for integrating Wormhole’s TypeScript SDK into your application to streamline USDC transfers across multiple chains. +## Configure Your Messaging Environment -## Core Concepts +1. Create a directory and initialize a Node.js project: -When bridging assets across chains, there are two primary approaches to handling the transfer process: manual and automated. Below, you may find the differences between these approaches and how they impact the user experience: + ```bash + mkdir core-message + cd core-message + npm init -y + ``` - - **Manual transfers** - manual transfers involve three key steps: initiating the transfer on the source chain, fetching the Circle attestation to verify the transfer, and completing the transfer on the destination chain +2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: - - **Automated transfers** - automatic transfers simplify the process by handling Circle attestations and finalization for you. With Wormhole's automated relaying, you only need to initiate the transfer, and the rest is managed for you + ```bash + npm install --save-dev tsx typescript @types/node ethers + ``` -## Prerequisites - -Before you begin, ensure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - [USDC tokens](https://faucet.circle.com/){target=\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples - - A wallet with a private key, funded with native tokens (Testnet or Mainnet) for gas fees - -## Supported Chains - -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains in the Wormhole SDK [GitHub repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/5810ebbd3635aaf1b5ab675da3f99f62aec2210f/core/base/src/constants/circle.ts#L14-L30){target=_blank}, which covers both Testnet and Mainnet environments. - -## Project Setup - -In this section, you'll set up your project for transferring USDC across chains using Wormhole's SDK and Circle's CCTP. We’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. - -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project +3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: ```bash - mkdir cctp-circle - cd cctp-circle - npm init -y + npx tsc --init ``` -2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control + Make sure your `tsconfig.json` includes the following settings: - ```bash - echo ".env" >> .gitignore + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } ``` -3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: ```bash - npm install @wormhole-foundation/sdk dotenv + npm install @wormhole-foundation/sdk ``` -4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project +5. Create a new file named `main.ts`: ```bash - touch .env + touch main.ts ``` - Inside the `.env` file, add your private key - - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - ``` +## Construct and Publish Your Message - !!! note - Ensure your private key contains USDC funds and native tokens for gas on both the source and destination chains. +1. Open `main.ts` and update the code there as follows: -5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, setting up signers for different chains, and managing transaction relays + ```ts title="main.ts" + import { + wormhole, + signSendWait, + toNative, + encoding, + type Chain, + type Network, + type NativeAddress, + type WormholeMessageId, + type UnsignedTransaction, + type TransactionId, + type WormholeCore, + type Signer as WormholeSdkSigner, + type ChainContext, +} from '@wormhole-foundation/sdk'; +// Platform-specific modules +import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; +import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; +import { + ethers, + Wallet, + JsonRpcProvider, + Signer as EthersSigner, +} from 'ethers'; - 1. Create the helpers file +/** + * The required value (SEPOLIA_PRIVATE_KEY) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ - ```bash - mkdir helpers - touch helpers/helpers.ts - ``` +const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; +// Provide a private endpoint RPC URL for Sepolia, defaults to a public node +// if not set +const RPC_URL = + process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; - 2. Open the `helpers.ts` file and add the following code +async function main() { + // Initialize Wormhole SDK + const network = 'Testnet'; + const wh = await wormhole(network, [EvmPlatformLoader]); + console.log('Wormhole SDK Initialized.'); - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { config } from 'dotenv'; -config(); + // Get the EVM signer and provider + let ethersJsSigner: EthersSigner; + let ethersJsProvider: JsonRpcProvider; -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; -} + try { + if (!SEPOLIA_PRIVATE_KEY) { + console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); + process.exit(1); + } -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} + ethersJsProvider = new JsonRpcProvider(RPC_URL); + const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); + ethersJsSigner = wallet.connect(ethersJsProvider); + console.log( + `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, + ); + } catch (error) { + console.error('Failed to get Ethers.js signer and provider:', error); + process.exit(1); + } -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; + // Define the source chain context + const sourceChainName: Chain = 'Sepolia'; + const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< + 'Testnet', + 'Sepolia', + 'Evm' + >; + console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), getEnv('ETH_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); + // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js + // signer using the Wormhole SDK's signing and transaction handling + // capabilities + let sdkSigner: WormholeSdkSigner; + try { + sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); + console.log( + `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, + ); + } catch (error) { + console.error('Failed to get Wormhole SDK Signer:', error); + process.exit(1); } - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} - - ``` - - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file + // Construct your message payload + const messageText = `HelloWormholeSDK-${Date.now()}`; + const payload: Uint8Array = encoding.bytes.encode(messageText); + console.log(`Message to send: "${messageText}"`); -6. **Create the main script** - create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains + // Define message parameters + const messageNonce = Math.floor(Math.random() * 1_000_000_000); + const consistencyLevel = 1; - 1. Create the `manual-transfer.ts` file in the `src` directory + try { + // Get the core protocol client + const coreProtocolClient: WormholeCore = + await sourceChainContext.getWormholeCore(); - ```bash - touch src/manual-transfer.ts - ``` + // Generate the unsigned transactions + const whSignerAddress: NativeAddress = toNative( + sdkSigner.chain(), + sdkSigner.address(), + ); + console.log( + `Preparing to publish message from ${whSignerAddress.toString()} on ${ + sourceChainContext.chain + }...`, + ); - 2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files + const unsignedTxs: AsyncGenerator> = + coreProtocolClient.publishMessage( + whSignerAddress, + payload, + messageNonce, + consistencyLevel, + ); - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; - ``` + // Sign and send the transactions + console.log( + 'Signing and sending the message publication transaction(s)...', + ); + const txIds: TransactionId[] = await signSendWait( + sourceChainContext, + unsignedTxs, + sdkSigner, + ); - - **`evm`** - this import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more - - **`solana`** - this adds support for Solana, a non-EVM chain - - **`getSigner`** - utility function from the helper file that retrieves the signer to sign transactions + if (!txIds || txIds.length === 0) { + throw new Error('No transaction IDs were returned from signSendWait.'); + } + const primaryTxIdObject = txIds[txIds.length - 1]; + const primaryTxid = primaryTxIdObject.txid; -## Manual Transfers + console.log(`Primary transaction ID for parsing: ${primaryTxid}`); + console.log( + `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, + ); -In a manual USDC transfer, you perform each step of the cross-chain transfer process individually. This approach allows for greater control and flexibility over how the transfer is executed, which can be helpful in scenarios where you need to customize certain aspects of the transfer, such as gas management, specific chain selection, or signing transactions manually. + console.log( + '\nWaiting a few seconds for transaction to propagate before parsing...', + ); + await new Promise((resolve) => setTimeout(resolve, 8000)); -This section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle’s CCTP. + // Retrieve VAA identifiers + console.log( + `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, + ); + const messageIds: WormholeMessageId[] = + await sourceChainContext.parseTransaction(primaryTxid); -### Set Up the Transfer Environment + if (messageIds && messageIds.length > 0) { + const wormholeMessageId = messageIds[0]; + console.log('--- VAA Identifiers (WormholeMessageId) ---'); + console.log(' Emitter Chain:', wormholeMessageId.chain); + console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); + console.log(' Sequence:', wormholeMessageId.sequence.toString()); + console.log('-----------------------------------------'); + } else { + console.error( + `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, + ); + } + } catch (error) { + console.error( + 'Error during message publishing or VAA identifier retrieval:', + error, + ); + if (error instanceof Error && error.stack) { + console.error('Stack Trace:', error.stack); + } + } +} -#### Configure Transfer Details +main().catch((e) => { + console.error('Critical error in main function (outer catch):', e); + if (e instanceof Error && e.stack) { + console.error('Stack Trace:', e.stack); + } + process.exit(1); +}); + ``` -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. + This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. -1. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM and Solana) to support. This allows us to interact with both EVM-compatible chains like Avalanche and non-EVM chains like Solana if needed +2. Run the script using the following command: - ```typescript - const wh = await wormhole('Testnet', [evm, solana]); + ```bash + npx tsx main.ts ``` - - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. -2. **Set up source and destination chains** - specify the source chain (Avalanche) and the destination chain (Sepolia) using the `getChain` method. This allows us to define where to send the USDC and where to receive them - - ```typescript - const rcvChain = wh.getChain('Sepolia'); - ``` + You will see terminal output similar to the following: -3. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains +
    +npx tsx main.ts +Wormhole SDK Initialized. +Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Source chain context obtained for: Sepolia +Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 +Message to send: "HelloWormholeSDK-1748362375390" +Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... +Signing and sending the message publication transaction(s)... +Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 +Waiting a few seconds for transaction to propagate before parsing... +Attempting to parse VAA identifiers from transaction: + 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... +--- VAA Identifiers (WormholeMessageId) --- + Emitter Chain: Sepolia + Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 + Sequence: 1 +----------------------------------------- + +
    - ```typescript - const destination = await getSigner(rcvChain); - ``` +3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages -4. **Define the transfer amount** - the amount of USDC to transfer is specified. In this case, we're transferring 0.1 USDC, which is parsed and converted into the base units expected by the Wormhole SDK +Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. - ```typescript - - ``` +## Next Steps -5. **Set transfer mode** - we specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - ```typescript - - ``` +- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +--- END CONTENT --- -#### Initiate the Transfer +Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +--- BEGIN CONTENT --- +--- +title: Get Started with Core Contracts +description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts +categories: Basics +--- -To begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain. +# Get Started with Core Contracts -1. **Create the Circle transfer object** - the `wh.circleTransfer()` function creates an object with the transfer details, such as the amount of USDC, the source and destination addresses, and the mode. However, this does not initiate the transfer itself +## Introduction - ```typescript - amt, - source.address, - destination.address, - automatic - ); - ``` +Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. -2. **Start the transfer** - the `initiateTransfer` function sends the transaction on the source chain. It involves signing and sending the transaction using the source signer. This will return a list of transaction IDs (`srcTxIds`) that you can use to track the transfer +While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. - ```typescript - console.log(`Started Transfer: `, srcTxids); - ``` +This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. -#### Fetch the Circle Attestation (VAA) +## Prerequisites -Once you initialize the transfer on the source chain, you must fetch the VAA from Circle. The VAA serves as cryptographic proof that CCTP has successfully recognized the transfer. The transfer cannot be completed on the destination chain until this attestation is fetched. +To interact with the Wormhole Core Contract, you'll need the following: +- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on +- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on +- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on -1. **Set a timeout** - fetching the attestation can take some time, so setting a timeout is common. In this example, we set the timeout to 60 seconds +## How to Interact with Core Contracts - ```typescript - - ``` +Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: -2. **Fetch the attestation** - after initiating the transfer, you can use the `fetchAttestation()` function to retrieve the VAA. This function will wait until the attestation is available or you reach the specified timeout +- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication +- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network - ```typescript - console.log(`Got Attestation: `, attestIds); - ``` +While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. - The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain +### Sending Messages -#### Complete the Transfer on the Destination Chain +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. -Once you fetch the VAA correctly, the final step is to complete the transfer on the destination chain (Sepolia in this example). This involves redeeming the VAA, which moves the USDC from Circle's custody onto the destination chain. +=== "EVM" -Use the `completeTransfer()` function to finalize the transfer on the destination chain. This requires the destination signer to sign and submit the transaction to the destination chain + The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: -```typescript -console.log(`Completed Transfer: `, dstTxids); + ```solidity + function publishMessage( + uint32 nonce, + bytes memory payload, + uint8 consistencyLevel +) external payable returns (uint64 sequence); + ``` - console.log('Circle Transfer status: ', xfer); + ??? interface "Parameters" - process.exit(0); -``` + `nonce` ++"uint32"++ + + A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. -The `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed + --- -You can find the full code for the manual USDC transfer script below: + `payload` ++"bytes memory"++ + + The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. -???- code "`manual-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from './helpers/helpers'; + --- -(async function () { - const wh = await wormhole('Testnet', [evm, solana]); + `consistencyLevel` ++"uint8"++ + + A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); + ??? interface "Returns" - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); + `sequence` ++"uint64"++ + + A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. + + ??? interface "Example" - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000n; + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); - const automatic = false; +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); - // Create the Circle transfer object - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); +// Check fee and send parameters - console.log('Circle Transfer object created:', xfer); +// Create the HelloWorldMessage struct +HelloWorldMessage memory parsedMessage = HelloWorldMessage({ + payloadID: uint8(1), + message: helloWorldMessage +}); - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); +// Encode the HelloWorldMessage struct into bytes +bytes memory encodedMessage = encodeMessage(parsedMessage); - // Wait for Circle Attestation (VAA) - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) - console.log('Waiting for Attestation'); - const attestIds = await xfer.fetchAttestation(timeout); - console.log(`Got Attestation: `, attestIds); +// Send the HelloWorld message by calling publishMessage on the +// wormhole core contract and paying the Wormhole protocol fee. +messageSequence = wormhole.publishMessage{value: wormholeFee}( + 0, // batchID + encodedMessage, + wormholeFinality() +); + ``` - // Complete the transfer on the destination chain (Sepolia) - console.log('Completing Transfer'); - const dstTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, dstTxids); + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - console.log('Circle Transfer status: ', xfer); +=== "Solana" - process.exit(0); -})(); - ``` + The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: -### Run Manual Transfer + ```rs + pub fn post_message<'info>( + ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, + batch_id: u32, + payload: Vec, + finality: Finality + ) -> Result<()> + ``` -To execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly + ??? interface "Parameters" -```bash -npx ts-node src/manual-transfer.ts -``` + `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ + + Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). -This will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia). + ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\_blank}. + ```rs + pub struct CpiContext<'a, 'b, 'c, 'info, T> + where + T: ToAccountMetas + ToAccountInfos<'info>, + { + pub accounts: T, + pub remaining_accounts: Vec>, + pub program: AccountInfo<'info>, + pub signer_seeds: &'a [&'b [&'c [u8]]], + } + ``` -### Complete Partial Transfer + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. -In some cases, a manual transfer might start but not finish—perhaps the user terminates their session, or there's an issue before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain. + ??? child "Type `PostMessage<'info>`" -This feature is handy for recovering an incomplete transfer or when debugging. + ```rs + pub struct PostMessage<'info> { + pub config: AccountInfo<'info>, + pub message: AccountInfo<'info>, + pub emitter: AccountInfo<'info>, + pub sequence: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub fee_collector: AccountInfo<'info>, + pub clock: AccountInfo<'info>, + pub rent: AccountInfo<'info>, + pub system_program: AccountInfo<'info>, + } + ``` -Here’s how you can complete a partial transfer using just the source chain and transaction hash: + For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. -```typescript -wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); + --- - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); -``` + `batch_id` ++"u32"++ + + An identifier for the message batch. -You will need to provide the below requirements to complete the partial transfer: + --- -- **Transaction ID (`txId`)** - the transaction hash from the source chain where the transfer was initiated -- **Signer for the destination chain (`destination.signer`)** - the wallet or private key that can authorize and complete the transfer on the destination chain. This signer is the same as the `destination.signer` defined in the manual transfer setup + `payload` ++"Vec"++ + + The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. -This allows you to resume the transfer process by rebuilding the transfer object and completing it on the destination chain. It's especially convenient when debugging or handling interrupted transfers. + --- -You can find the full code for the manual USDC transfer script below: + `finality` ++"Finality"++ + + Specifies the level of finality or confirmation required for the message. + + ??? child "Type `Finality`" -??? code "`partial-transfer.ts`" - ```typescript - import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; + ```rs + pub enum Finality { + Confirmed, + Finalized, + } + ``` + + ??? interface "Returns" -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); + ++"Result<()>"++ + + The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error + + ??? interface "Example" - // Grab chain Contexts -- these hold a reference to a cached rpc client - const rcvChain = wh.getChain('Sepolia'); + ```rust + let fee = ctx.accounts.wormhole_bridge.fee(); +// ... Check fee and send parameters - // Get signer from local key - const destination = await getSigner(rcvChain); +let config = &ctx.accounts.config +let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; - const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds) +// Invoke `wormhole::post_message`. +wormhole::post_message( + CpiContext::new_with_signer( + ctx.accounts.wormhole_program.to_account_info(), + wormhole::PostMessage { + // ... Set fields + }, + &[ + // ... Set seeds + ], + ), + config.batch_id, + payload, + config.finality.into(), +)?; + ``` - // Rebuild the transfer from the source txid - const xfer = await CircleTransfer.from( - wh, - { - chain: 'Avalanche', - txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd', - }, - timeout - ); + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. - const dstTxIds = await xfer.completeTransfer(destination.signer); - console.log('Completed transfer: ', dstTxIds); +Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - console.log('Circle Transfer status: ', xfer); +VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. - process.exit(0); -})(); - ``` +### Receiving Messages -## Automatic Transfers +The way a message is received and handled depends on the environment. -The automatic transfer process simplifies the steps by automating the attestation fetching and transfer completion. All you need to do is initiate the transfer. +=== "EVM" -### Set Up the Transfer Environment + On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. -#### Configure Transfer Details + ```solidity + function parseAndVerifyVM( + bytes calldata encodedVM +) external view returns (VM memory vm, bool valid, string memory reason); + ``` -The setup for automatic transfers is similar to manual transfers, with the key difference being that the `automatic` flag is `true`. This indicates that Wormhole will handle the attestation and finalization steps for you + ??? interface "Parameters" -```typescript + `encodedVM` ++"bytes calldata"++ + + The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. -``` + ??? interface "Returns" -#### Initiate the Transfer + `vm` ++"VM memory"++ + + The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. -The transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain + ??? child "Struct `VM`" -```typescript -amt, - source.address, - destination.address, - automatic - ); -``` + ```solidity + struct VM { + uint8 version; + uint32 timestamp; + uint32 nonce; + uint16 emitterChainId; + bytes32 emitterAddress; + uint64 sequence; + uint8 consistencyLevel; + bytes payload; + uint32 guardianSetIndex; + Signature[] signatures; + bytes32 hash; + } + ``` -#### Log Transfer Details + For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. -After initiating the transfer, you can log the transaction IDs for both the source and destination chains. This will help you track the progress of the transfer + --- + + `valid` ++"bool"++ + + A boolean indicating whether the VAA is valid or not. + + --- -```typescript -console.log(`Started Transfer: `, srcTxids); + `reason` ++"string"++ + + If the VAA is not valid, a reason will be provided - process.exit(0); -``` + ??? interface "Example" -You can find the full code for the automatic USDC transfer script below: + ```solidity + function receiveMessage(bytes memory encodedMessage) public { + // Call the Wormhole core contract to parse and verify the encodedMessage + ( + IWormhole.VM memory wormholeMessage, + bool valid, + string memory reason + ) = wormhole().parseAndVerifyVM(encodedMessage); -??? code "`automatic-transfer.ts`" - ```typescript - import { wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import { getSigner } from '../helpers/helpers'; + // Perform safety checks here -(async function () { - // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana) - const wh = await wormhole('Testnet', [evm, solana]); + // Decode the message payload into the HelloWorldMessage struct + HelloWorldMessage memory parsedMessage = decodeMessage( + wormholeMessage.payload + ); - // Set up source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Sepolia'); + // Your custom application logic here +} + ``` - // Configure the signers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals) - const amt = 100_000_001n; +=== "Solana" - const automatic = true; + On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. - // Create the Circle transfer object (USDC-only) - const xfer = await wh.circleTransfer( - amt, - source.address, - destination.address, - automatic - ); + Retrieve the raw message data: - console.log('Circle Transfer object created:', xfer); + ```rs + let posted_message = &ctx.accounts.posted; + posted_message.data() + ``` - // Initiate the transfer on the source chain (Avalanche) - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); + ??? interface "Example" - process.exit(0); -})(); - ``` + ```rust + pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { + let posted_message = &ctx.accounts.posted -### Run Automatic Transfer + if let HelloWorldMessage::Hello { message } = posted_message.data() { + // Check message + // Your custom application logic here + Ok(()) + } else { + Err(HelloWorldError::InvalidMessage.into()) + } +} + + ``` -Assuming you have created a new `automatic-transfer.ts` file for automatic transfers under the `src` directory, use the following command to run it with `ts-node`: + View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. -```bash -npx ts-node src/automatic-transfer.ts +#### Validating the Emitter + +When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. + +Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: + +```solidity +require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); ``` -The automatic relayer will take care of fetching the attestation and completing the transfer for you. +This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. -## Resources +```typescript +const tx = await receiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) +); -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\_blank}. The repository includes all the example scripts and configurations needed to perform USDC cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK and Circle's CCTP. +await tx.wait(); +``` -## Conclusion +#### Additional Checks -In this tutorial, you’ve gained hands-on experience with Circle’s CCTP and the Wormhole SDK. You’ve learned to perform manual and automatic USDC transfers across multiple chains and recover partial transfers if needed. +In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: -By following these steps, you've learned how to: +- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? +- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? -- Set up cross-chain transfers for native USDC between supported chains -- Handle both manual and automatic relaying of transactions -- Recover and complete incomplete transfers using the transaction hash and the destination chain’s signer +The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. + +## Source Code References + +For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: + +- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} +- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} +- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) +- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} +- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} +- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} +- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/concepts/routes/ +Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ --- BEGIN CONTENT --- --- -title: Routes -description: Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. -categories: Connect, Transfer +title: Wormhole-Deployed Relayers +description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. +categories: Relayers, Basics --- -## Routes Overview {: #routes-overview} +# Wormhole Relayer -This page explains the concept of routes in Wormhole Connect. To configure routes for your widget, check the [Wormhole Connect Configuration](/docs/products/connect/configuration/data/){target=\_blank}. +## Introduction -Routes are methods by which the widget will transfer the assets. Wormhole Connect supports Token Bridge transfers for any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX. +The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. -When you select the source chain, source token, and destination chain, Wormhole Connect will display the best routes available for that particular combination. In practice, if routes other than the Token Bridge are available, only those will be displayed. Check the [feature matrix](/docs/products/connect/reference/support-matrix/){target=\_blank} to see under which exact conditions the routes appear. +This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. -## Token Bridge Routes {: #token-bridge-routes} +## Get Started with the Wormhole Relayer -The Token Bridge is Wormhole's best-known transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. +Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. -#### Manual Route {: #manual-route} +To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. -The manual route transfer method requires two transactions: one on the origin chain to lock the tokens (or burn the Wormhole-wrapped tokens) and one on the destination chain to mint the Wormhole-wrapped tokens (or unlock the original tokens). To offer this option, enable the `bridge` route in the configuration. +
    + ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) +
    The components outlined in blue must be implemented.
    +
    -#### Automatic Route {: #automatic-route} +### Wormhole Relayer Interfaces -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically - for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `relay` route is enabled in the configuration. +There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: -## CCTP Routes (USDC) {: #cctp-routes-usdc} - -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. Wormhole Connect can facilitate such transfers. +- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs +- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract +- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from -Note that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native USDC. +## Interact with the Wormhole Relayer -#### Manual Route {: #manual-route-cctp} +To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. -This transfer method requires two transactions: one on the origin chain to burn the USDC and one on the destination chain to mint the USDC. The manual CCTP route relies on CCTP only and doesn't use Wormhole messaging in the background. Enable the `cctpManual` route in the configuration to offer this option. +To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. -#### Automatic Route {: #automatic-route-cctp} +To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. -Trustless relayers can execute the second transaction on the user's behalf. Therefore, the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. To offer this option, enable the `cctpRelay` route in the configuration. +Your initial set up should resemble the following: -## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes} +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; -[Wormhole's Native Token Transfer (NTT) framework](https://github.com/wormhole-foundation/native-token-transfers/){target=\_blank} enables token issuers to retain full ownership of their tokens across any number of chains, unlike the Token Bridge. The token issuer must deploy NTT contracts, and Wormhole Connect needs to be [configured](/docs/products/connect/configuration/data/){target=\_blank} with the appropriate `nttGroups` before such tokens are recognized as transferrable via NTT. Refer to the [documentation in the NTT repository](https://github.com/wormhole-foundation/native-token-transfers?tab=readme-ov-file#overview){target=\_blank} for more information about the contracts needed and the framework in general. +import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; -#### Manual Route {: #manual-route-ntt} +contract Example { + IWormholeRelayer public wormholeRelayer; -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To offer this option, enable the `nttManual` route in the configuration. + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } +} +``` -#### Automatic Route {: #automatic-route-ntt} +The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. -Trustless relayers can execute the second transaction on the user's behalf, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. Wormhole Connect automatically detects whether the relayer supports a token and will display the option if the `nttRelay` route is enabled in the configuration. +### Send a Message -## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth} +To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. For example, you can transfer native ETH from Arbitrum to Optimism and end up with Optimism ETH all in one go. Supported chains are Ethereum, Arbitrum, Optimism, Base, Polygon (canonical wETH), BSC (canonical wETH), and Avalanche (canonical wETH). +```solidity +function sendPayloadToEvm( + // Chain ID in Wormhole format + uint16 targetChain, + // Contract Address on target chain we're sending a message to + address targetAddress, + // The payload, encoded as bytes + bytes memory payload, + // How much value to attach to the delivery transaction + uint256 receiverValue, + // The gas limit to set on the delivery transaction + uint256 gasLimit +) external payable returns ( + // Unique, incrementing ID, used to identify a message + uint64 sequence +); +``` -#### Automatic Route {: #automatic-route-eth} +!!! tip + To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. -Only the relayed route is available due to the complexity of the transaction that needs to be executed at the destination. To offer this option, enable the `ethBridge` and/or `wstETHBridge` route in the configuration to provide this option. +The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. -## USDT Bridge Route {: #usdt-bridge-route} +```solidity +function quoteEVMDeliveryPrice( + // Chain ID in Wormhole format + uint16 targetChain, + // How much value to attach to delivery transaction + uint256 receiverValue, + // The gas limit to attach to the delivery transaction + uint256 gasLimit +) external view returns ( + // How much value to attach to the send call + uint256 nativePriceQuote, + uint256 targetChainRefundPerGasUnused +); +``` -Operating on the same technology as the ETH Bridge, this route can transfer USDT between certain EVMs without going through the native bridges. The resulting token will be the canonical USDT token on the destination instead of the Wormhole-wrapped variant. Supported chains are Ethereum, Polygon, Avalanche, Arbitrum, Optimism, BSC, and Base. +This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. -#### Automatic Route {: #automatic-route-usdt} +In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: -Only the relayed route is available due to the complexity of the transaction that needs to be executed on the destination. Enable the `usdtBridge` route in the configuration to offer this option. +```solidity +// Get a quote for the cost of gas for delivery +(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + valueToSend, + GAS_LIMIT +); -## tBTC Route {: #tbtc-route} +// Send the message +wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(payload), + valueToSend, + GAS_LIMIT +); +``` -You can bridge [Threshold's Bitcoin](https://threshold.network/){target=\_blank} via this hybrid solution that combines the Token Bridge and Threshold's contracts. Native tBTC is first locked in the Wormhole Token Bridge, transferred to the destination in the form of Wormhole-wrapped tBTC, which is then immediately locked in Threshold's contract that mints native tBTC for it. The net result is that the user ends up with native tBTC on chains where this Threshold contract is deployed (e.g., Solana, Polygon, Arbitrum, Optimism, or Base). +### Receive a Message -Note that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through the Token Bridge, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC. +To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). -#### Manual Route {: #manual-route-tbtc} +```solidity +function receiveWormholeMessages( + bytes memory payload, // Message passed by source contract + bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) + bytes32 sourceAddress, // The address of the source contract + uint16 sourceChain, // The Wormhole chain ID + bytes32 deliveryHash // A hash of contents, useful for replay protection +) external payable; +``` -This transfer method requires two transactions: one on the origin chain to burn or lock the tokens and one on the destination chain to mint them. To provide this option, enable the `tbtc` route in the configuration. ---- END CONTENT --- +The logic inside the function body may be whatever business logic is required to take action on the specific payload. -Doc-Content: https://wormhole.com/docs/products/connect/configuration/configuration-v0/ ---- BEGIN CONTENT --- ---- -title: Configure Your Connect Widget v0 -description: Configure Wormhole Connect v0 for React or HTML, set themes, define tokens, networks, and customize RPC endpoints for optimized blockchain interactions. ---- +## Delivery Guarantees -# Configure Your Connect Widget +The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. -## Introduction {: #introduction } +This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. -Wormhole Connect is a flexible React widget that streamlines cross-chain asset transfers and enables seamless interoperability by leveraging Wormhole's powerful infrastructure. Designed for easy integration into decentralized applications (dApps), Wormhole Connect abstracts the complexities of cross-chain communication, providing a user-friendly experience for both developers and end users. +Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. -This guide provides detailed instructions on configuring Wormhole Connect and highlights the many ways it can be customized to fit your specific needs, from integrating supported blockchains and tokens to tailoring the user interface. +## Delivery Statuses -!!! note - For documentation on the latest version of Connect, please refer to the current [configuration documentation](/docs/products/connect/configuration/data/){target=\_blank}. If you are looking to upgrade from Wormhole Connect v0 to v1, please refer to the [migration guide](/docs/products/connect/guides/upgrade/){target=\_blank} for detailed instructions. +All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: -## Get Started +- (0) Delivery Success +- (1) Receiver Failure +- (2) Forward Request Success +- (3) Forward Request Failure -Configure the Wormhole Connect React component by passing a `WormholeConnectConfig` object as the `config` attribute. If using the hosted version, provide `config` and `theme` as JSON-serialized strings on the mount point. +A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: -=== "React" +- The target contract does not implement the `IWormholeReceiver` interface +- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` +- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` - ```ts - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - networks: ['ethereum', 'polygon', 'solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - ethereum: 'https://rpc.ankr.com/eth', - solana: 'https://rpc.ankr.com/solana', - } -} - - - ``` +All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. -=== "HTML Tags" +`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. - ```html -
    - ``` +## Other Considerations -## Examples {: #examples } +Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: -Below are some examples of different ways you can configure Connect. See `WormholeConnectConfig` in the below file for a full view of the supported configuration parameters. +- Receiving a message from a relayer +- Checking for expected emitter +- Calling `parseAndVerify` on any additional VAAs +- Replay protection +- Message ordering (no guarantees on order of messages delivered) +- Forwarding and call chaining +- Refunding overpayment of `gasLimit` +- Refunding overpayment of value sent -??? code "View `WormholeConnectConfig`" - ```ts - import { - ChainName, - WormholeContext, - WormholeConfig, - ChainResourceMap, -} from 'sdklegacy'; -import MAINNET from './mainnet'; -import TESTNET from './testnet'; -import DEVNET from './devnet'; -import type { WormholeConnectConfig } from './types'; -import { - Network, - InternalConfig, - Route, - WrappedTokenAddressCache, -} from './types'; -import { - mergeCustomTokensConfig, - mergeNttGroups, - validateDefaults, -} from './utils'; -import { wrapEventHandler } from './events'; +## Track the Progress of Messages with the Wormhole CLI -import { SDKConverter } from './converter'; +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: -import { - wormhole as getWormholeV2, - Wormhole as WormholeV2, - Network as NetworkV2, - Token as TokenV2, - Chain as ChainV2, - ChainTokens as ChainTokensV2, - WormholeConfigOverrides as WormholeConfigOverridesV2, -} from '@wormhole-foundation/sdk'; +=== "Mainnet" -import '@wormhole-foundation/sdk/addresses'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import sui from '@wormhole-foundation/sdk/sui'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import algorand from '@wormhole-foundation/sdk/algorand'; + ```bash + worm status mainnet ethereum INSERT_TRANSACTION_HASH + ``` -export function buildConfig( - customConfig?: WormholeConnectConfig -): InternalConfig { - const network = ( - customConfig?.network || - customConfig?.env || // TODO remove; deprecated - import.meta.env.REACT_APP_CONNECT_ENV?.toLowerCase() || - 'mainnet' - ).toLowerCase() as Network; +=== "Testnet" - if (!['mainnet', 'testnet', 'devnet'].includes(network)) - throw new Error(`Invalid env "${network}"`); + ```bash + worm status testnet ethereum INSERT_TRANSACTION_HASH + ``` - const networkData = { MAINNET, DEVNET, TESTNET }[network.toUpperCase()]!; +See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. - const tokens = mergeCustomTokensConfig( - networkData.tokens, - customConfig?.tokensConfig - ); +## Step-by-Step Tutorial - const sdkConfig = WormholeContext.getConfig(network); +For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. +--- END CONTENT --- - const rpcs = Object.assign( - {}, - sdkConfig.rpcs, - networkData.rpcs, - customConfig?.rpcs - ); +Doc-Content: https://wormhole.com/docs/products/messaging/overview/ +--- BEGIN CONTENT --- +--- +title: Messaging Overview +description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Basics +--- - const wh = getWormholeContext(network, sdkConfig, rpcs); +# Messaging Overview - if (customConfig?.bridgeDefaults) { - validateDefaults(customConfig.bridgeDefaults, networkData.chains, tokens); - } +Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. - const sdkConverter = new SDKConverter(wh); +## Key Features - return { - wh, - sdkConfig, - sdkConverter, +- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems +- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity +- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases - v2Network: sdkConverter.toNetworkV2(network), +## How It Works - network, - isMainnet: network === 'mainnet', - // External resources - rpcs, - rest: Object.assign( - {}, - sdkConfig.rest, - networkData.rest, - customConfig?.rest - ), - graphql: Object.assign({}, networkData.graphql, customConfig?.graphql), - wormholeApi: { - mainnet: 'https://api.wormholescan.io/', - testnet: 'https://api.testnet.wormholescan.io/', - devnet: '', - }[network], - wormholeRpcHosts: { - mainnet: [ - 'https://wormhole-v2-mainnet-api.mcf.rocks', - 'https://wormhole-v2-mainnet-api.chainlayer.network', - 'https://wormhole-v2-mainnet-api.staking.fund', - ], - testnet: [ - 'https://guardian.testnet.xlabs.xyz', - 'https://guardian-01.testnet.xlabs.xyz', - 'https://guardian-02.testnet.xlabs.xyz', - ], - devnet: ['http://localhost:7071'], - }[network], - coinGeckoApiKey: customConfig?.coinGeckoApiKey, +The messaging flow consists of several core components: - // Callbacks - triggerEvent: wrapEventHandler(customConfig?.eventHandler), - validateTransfer: customConfig?.validateTransferHandler, +1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain +4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic - // White lists - chains: networkData.chains, - chainsArr: Object.values(networkData.chains).filter((chain) => { - return customConfig?.networks - ? customConfig.networks!.includes(chain.key) - : true; - }), - tokens, - tokensArr: Object.values(tokens).filter((token) => { - return customConfig?.tokens - ? customConfig.tokens!.includes(token.key) - : true; - }), +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - // For token bridge ^_^ - wrappedTokenAddressCache: new WrappedTokenAddressCache( - tokens, - sdkConverter - ), +## Use Cases - gasEstimates: networkData.gasEstimates, - // TODO: routes that aren't supported yet are disabled - routes: (customConfig?.routes ?? Object.values(Route)).filter((r) => - [ - Route.Bridge, - Route.Relay, - Route.NttManual, - Route.NttRelay, - Route.CCTPManual, - Route.CCTPRelay, - ].includes(r as Route) - ), +Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. - // UI details - cta: customConfig?.cta, - explorer: customConfig?.explorer, - attestUrl: { - mainnet: 'https://portalbridge.com/advanced-tools/#/register', - devnet: '', - testnet: - 'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register', - }[network], - bridgeDefaults: customConfig?.bridgeDefaults, - cctpWarning: customConfig?.cctpWarning?.href || '', - pageHeader: customConfig?.pageHeader, - pageSubHeader: customConfig?.pageSubHeader, - menu: customConfig?.menu ?? [], - searchTx: customConfig?.searchTx, - moreTokens: customConfig?.moreTokens, - moreNetworks: customConfig?.moreNetworks, - partnerLogo: customConfig?.partnerLogo, - walletConnectProjectId: - customConfig?.walletConnectProjectId ?? - import.meta.env.REACT_APP_WALLET_CONNECT_PROJECT_ID, - showHamburgerMenu: customConfig?.showHamburgerMenu ?? false, - previewMode: !!customConfig?.previewMode, +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - // Route options - ethBridgeMaxAmount: customConfig?.ethBridgeMaxAmount ?? 5, - wstETHBridgeMaxAmount: customConfig?.wstETHBridgeMaxAmount ?? 5, + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time - // NTT config - nttGroups: mergeNttGroups( - tokens, - networkData.nttGroups, - customConfig?.nttGroups - ), +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - // Guardian set - guardianSet: networkData.guardianSet, + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources - // Render redesign views - useRedesign: customConfig?.useRedesign, - }; -} +- **Gas Abstraction** -// Running buildConfig with no argument generates the default configuration -const config = buildConfig(); -export default config; + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps -// TODO SDKV2: REMOVE -export function getWormholeContext( - network: Network, - sdkConfig: WormholeConfig, - rpcs: ChainResourceMap -): WormholeContext { - const wh: WormholeContext = new WormholeContext(network, { - ...sdkConfig, - ...{ rpcs }, - }); +- **Bridging Intent Library** - return wh; -} + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents -export function getDefaultWormholeContext(network: Network): WormholeContext { - const sdkConfig = WormholeContext.getConfig(network); - const networkData = { mainnet: MAINNET, devnet: DEVNET, testnet: TESTNET }[ - network - ]!; +- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - const rpcs = Object.assign({}, sdkConfig.rpcs, networkData.rpcs); + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards - return getWormholeContext(network, sdkConfig, rpcs); -} +## Next Steps -export async function getWormholeContextV2(): Promise> { - if (config.v2Wormhole) return config.v2Wormhole; - config.v2Wormhole = await newWormholeContextV2(); - return config.v2Wormhole; -} +Follow these steps to work with Wormhole Messaging: -export async function newWormholeContextV2(): Promise> { - const v2Config: WormholeConfigOverridesV2 = { chains: {} }; +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +--- END CONTENT --- - for (const key in config.chains) { - const chainV1 = key as ChainName; - const chainConfigV1 = config.chains[chainV1]!; +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ +--- BEGIN CONTENT --- +--- +title: Create Cross-Chain Contracts +description: Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. +--- - const chainContextV1 = chainConfigV1.context; +# Create Cross-Chain Messaging Contracts - const chainV2 = config.sdkConverter.toChainV2( - chainV1 as ChainName - ) as ChainV2; +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} - const rpc = config.rpcs[chainV1]; - const tokenMap: ChainTokensV2 = {}; +## Introduction - for (const token of config.tokensArr) { - const nativeChainV2 = config.sdkConverter.toChainV2(token.nativeChain); +Wormhole's cross-chain messaging allows smart contracts to interact seamlessly across multiple blockchains. This enables developers to build decentralized applications that leverage the strengths of different networks, whether it's Avalanche, Celo, Ethereum, or beyond. In this tutorial, we'll explore using [Wormhole's Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} to create cross-chain contracts to send and receive messages across chains. - const tokenV2: Partial = { - key: token.key, - chain: chainV2, - symbol: token.symbol, - }; +Wormhole's messaging infrastructure simplifies data transmission, event triggering, and transaction initiation across blockchains. In this tutorial, we'll guide you through a simple yet powerful hands-on demonstration that showcases this practical capability. We'll deploy contracts on two Testnets—Avalanche Fuji and Celo Alfajores—and send messages from one chain to another. This tutorial is perfect for those new to cross-chain development and seeking hands-on experience with Wormhole's powerful toolkit. - if (nativeChainV2 == chainV2) { - const decimals = - token.decimals[chainContextV1] ?? token.decimals.default; - if (!decimals) { - continue; - } else { - tokenV2.decimals = decimals; - } - const address = config.sdkConverter.getNativeTokenAddressV2(token); - if (!address) throw new Error('Token must have address'); - tokenV2.address = address; - } else { - tokenV2.original = nativeChainV2; - if (token.foreignAssets) { - const fa = token.foreignAssets[chainV1]!; +By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. - if (!fa) { - continue; - } else { - tokenV2.address = fa.address; - tokenV2.decimals = fa.decimals; - } - } else { - continue; - } - } +This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. - tokenMap[token.key] = tokenV2 as TokenV2; - } +## Wormhole Overview - v2Config.chains![chainV2] = { rpc, tokenMap }; - } +We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. - return await getWormholeV2( - config.v2Network, - [evm, solana, aptos, cosmwasm, sui, algorand], - v2Config - ); -} +Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. -// setConfig can be called afterwards to override the default config with integrator-provided config -export function setConfig(customConfig?: WormholeConnectConfig) { - const newConfig: InternalConfig = buildConfig(customConfig); +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - // We overwrite keys in the existing object so the references to the config - // imported elsewhere point to the new values - for (const key in newConfig) { - /* @ts-ignore */ - config[key] = newConfig[key]; - } -} +## Prerequisites -// TODO: add config validation step to buildConfig -//validateConfigs(); - - ``` +Before starting this tutorial, ensure you have the following: -### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints } +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts +- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees +- Wallet private key -Specify supported networks, tokens, and custom RPC endpoints. Your users may encounter rate limits using public RPC endpoints if you don't provide your own. +## Build Cross-Chain Messaging Contracts -=== "Mainnet" +In this section, we'll deploy two smart contracts: one to send a message from Avalanche Fuji and another to receive it on Celo Alfajores. The contracts interact with the Wormhole relayer to transmit messages across chains. - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +At a high level, our contracts will: -const config: WormholeConnectConfig = { - env: 'mainnet', - networks: ['ethereum', 'polygon', 'solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - ethereum: 'https://rpc.ankr.com/eth', - solana: 'https://rpc.ankr.com/solana', - }, -}; +1. Send a message from Avalanche to Celo using the Wormhole relayer +2. Receive and process the message on Celo, logging the content of the message -function App() { - return ; -} - ``` +Before diving into the deployment steps, let's first break down key parts of the contracts. -=== "Testnet" +### Sender Contract: MessageSender - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +The `MessageSender` contract is responsible for quoting the cost of sending a message cross-chain and then sending that message. -const config: WormholeConnectConfig = { - env: 'testnet', - networks: ['sepolia', 'arbitrum_sepolia', 'base_sepolia', 'fuji'], +Key functions include: - rpcs: { - fuji: 'https://rpc.ankr.com/avalanche_fuji', - base_sepolia: 'https://base-sepolia-rpc.publicnode.com', - }, -}; + - **`quoteCrossChainCost`** - calculates the cost of delivering a message to the target chain using the Wormhole relayer + - **`sendMessage`** - encodes the message and sends it to the target chain and contract address using the Wormhole relayer -function App() { - return ; -} - ``` +Here's the core of the contract: -!!! note - For a complete list of testnet chain names that can be manually added, see the [Testnet Chains List](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/tokenRegistry/src/scripts/importConnect.ts#L44-L55){target=\_blank}. +```solidity +uint16 targetChain, + address targetAddress, + string memory message + ) external payable { + uint256 cost = quoteCrossChainCost(targetChain); -### Fully Customized Theme {: #fully-customized-theme } + require( + msg.value >= cost, + "Insufficient funds for cross-chain delivery" + ); -Wormhole Connect offers a high level of customizability that suits and integrates with your application's design, including various options for buttons, backgrounds, popovers, fonts, and more. The following example demonstrates a variety of appearance customizations. Remember, if you prefer a visual to aid in designing your widget, you can use the [no code style interface](https://connect-in-style.wormhole.com/){target=\_blank}. + wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(message, msg.sender), + 0, + GAS_LIMIT + ); + } +``` -```jsx -import WormholeConnect, { - WormholeConnectTheme, -} from '@wormhole-foundation/wormhole-connect'; -import red from '@mui/material/colors/red'; -import lightblue from '@mui/material/colors/lightBlue'; -import grey from '@mui/material/colors/grey'; -import green from '@mui/material/colors/green'; -import orange from '@mui/material/colors/orange'; +You can find the full code for the `MessageSender.sol` below. -const customTheme: WormholeConnectTheme = { - mode: 'dark', - primary: grey, - secondary: grey, - divider: 'rgba(255, 255, 255, 0.2)', - background: { - default: '#232323', - }, - text: { - primary: '#ffffff', - secondary: grey[500], - }, - error: red, - info: lightblue, - success: green, - warning: orange, - button: { - primary: 'rgba(255, 255, 255, 0.2)', - primaryText: '#ffffff', - disabled: 'rgba(255, 255, 255, 0.1)', - disabledText: 'rgba(255, 255, 255, 0.4)', - action: orange[300], - actionText: '#000000', - hover: 'rgba(255, 255, 255, 0.7)', - }, - options: { - hover: '#474747', - select: '#5b5b5b', - }, - card: { - background: '#333333', - secondary: '#474747', - elevation: 'none', - }, - popover: { - background: '#1b2033', - secondary: 'rgba(255, 255, 255, 0.5)', - elevation: 'none', - }, - modal: { - background: '#474747', - }, - font: { - primary: 'Impact', - header: 'Impact', - }, -}; +??? code "MessageSender.sol" -export default function App() { - return ; -} -``` + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; -### Environment {: #environment } +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; -You can configure Connect to be used in Testnet environments, too. You can toggle between Mainnet and Testnet environments by defining the `WormholeConnectConfig` as follows: +contract MessageSender { + IWormholeRelayer public wormholeRelayer; + uint256 constant GAS_LIMIT = 50000; -=== "Mainnet" + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } - ```ts - const config: WormholeConnectConfig = { - env: 'mainnet', - }; - ``` + function quoteCrossChainCost( + uint16 targetChain + ) public view returns (uint256 cost) { + (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); + } -=== "Testnet" + function sendMessage( + uint16 targetChain, + address targetAddress, + string memory message + ) external payable { + uint256 cost = quoteCrossChainCost(targetChain); - ```ts - const config: WormholeConnectConfig = { - env: 'testnet', - }; + require( + msg.value >= cost, + "Insufficient funds for cross-chain delivery" + ); + + wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(message, msg.sender), + 0, + GAS_LIMIT + ); + } +} ``` -### Custom RPC Endpoint {: #custom-rpc-endpoint } -You can define a custom RPC provider for your Connect widget to use. This can be especially helpful if you'd like to replace public endpoints with dedicated or private endpoints. +### Receiver Contract: MessageReceiver -```ts -const config: WormholeConnectConfig = { - rpcs: { - solana: 'https://rpc.ankr.com/solana/ee827255553bb0fa9e0aaeab27e988707e60ea06ae36be0658b778072e94979e', - }, -}; -``` +The `MessageReceiver` contract handles incoming cross-chain messages. When a message arrives, it decodes the payload and logs the message content. It ensures that only authorized contracts can send and process messages, adding an extra layer of security in cross-chain communication. -### Arbitrary Token {: #arbitrary-token } +#### Emitter Validation and Registration -The following section shows how to add an arbitrary token to your deployment of Connect. +In cross-chain messaging, validating the sender is essential to prevent unauthorized contracts from sending messages. The `isRegisteredSender` modifier ensures that messages can only be processed if they come from the registered contract on the source chain. This guards against malicious messages and enhances security. -!!! note - You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with Connect. +Key implementation details include: -This example configuration limits Connect to the Solana and Ethereum networks and a handful of tokens, including `BSKT`, which isn't built in by default and provided under the `tokensConfig` key. + - **`registeredSender`** - stores the address of the registered sender contract + - **`setRegisteredSender`** - registers the sender's contract address on the source chain. It ensures that only registered contracts can send messages, preventing unauthorized senders + - **`isRegisteredSender`** - restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication -See [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. +```solidity -```json -const config: WormholeConnectConfig = { - networks: ['solana', 'ethereum'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC', 'BSKT'], - tokensConfig: { - BSKT: { - key: 'BSKT', - symbol: 'BSKT', - nativeChain: 'solana', - tokenId: { - chain: 'solana', - address: '6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA', - }, - coinGeckoId: 'basket', - icon: 'https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891', - color: '#2894EE', - decimals: { - default: 5, - }, - }, - }, -}; +require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } + + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } ``` -## More Configuration Options {: #more-configuration-options } +#### Message Processing -### Whitelisting Tokens {: #whitelisting-tokens } +The `receiveWormholeMessages` is the core function that processes the received message. It checks that the Wormhole relayer sent the message, decodes the payload, and emits an event with the message content. It is essential to verify the message sender to prevent unauthorized messages. -By default, Connect will offer its complete built-in list of assets, but you can restrict the displayed assets by defining a subset of tokens under `tokens`. The default full list is as follows: +```solidity +bytes memory payload, + bytes[] memory, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 + ) public payable override isRegisteredSender(sourceChain, sourceAddress) { + require( + msg.sender == address(wormholeRelayer), + "Only the Wormhole relayer can call this function" + ); -| Mainnet | Testnet | -|:--------------:|:----------------------------------:| -| ETH | ETH, ETHsepolia | -| WETH | WETH, WETHsepolia | -| USDCeth | USDCeth | -| WBTC | - | -| USDT | - | -| DAI | - | -| BUSD | - | -| MATIC | MATIC | -| WMATIC | WMATIC | -| USDCpolygon | - | -| BNB | BNB | -| WBNB | WBNB | -| USDCbnb | - | -| AVAX | AVAX | -| WAVAX | WAVAX | -| USDCavax | USDCavax | -| FTM | FTM | -| WFTM | WFTM | -| CELO | CELO | -| GLMR | GLMR | -| WGLMR | WGLMR | -| SOL | WSOL | -| PYTH | - | -| SUI | SUI | -| USDCsol | - | -| APT | APT | -| ETHarbitrum | ETHarbitrum, ETHarbitrum_sepolia | -| WETHarbitrum | WETHarbitrum, WETHarbitrum_sepolia | -| USDCarbitrum | USDCarbitrum | -| ETHoptimism | ETHoptimism, ETHoptimism_sepolia | -| WETHoptimism | WETHoptimism, WETHoptimism_sepolia | -| USDCoptimism | USDCoptimism | -| ETHbase | ETHbase, ETHbase_sepolia | -| WETHbase | WETHbase, WETHbase_sepolia | -| tBTC | tBTC | -| tBTCpolygon | tBTCpolygon | -| tBTCoptimism | tBTCoptimism | -| tBTCarbitrum | tBTCarbitrum | -| tBTCbase | tBTCbase | -| tBTCsol | tBTCsol | -| WETHpolygon | - | -| WETHbsc | - | -| wstETH | wstETH | -| wstETHarbitrum | - | -| wstETHoptimism | - | -| wstETHpolygon | - | -| wstETHbase | - | + // Decode the payload to extract the message + string memory message = abi.decode(payload, (string)); -### Routes {: #routes } + // Example use of sourceChain for logging + if (sourceChain != 0) { + emit SourceChainLogged(sourceChain); + } -By default, Connect will offer its complete built-in list of routes, but you can restrict the possible route assets by defining a subset under `routes.` By default, Connect will offer its complete built-in list: + // Emit an event with the received message + emit MessageReceived(message); + } +``` -| Mainnet | Testnet | -|:------------:|:----------:| -| bridge | bridge | -| relay | relay | -| cctpManual | cctpManual | -| cctpRelay | cctpRelay | -| nttManual | nttManual | -| nttRelay | nttRelay | -| ethBridge | - | -| wstETHBridge | - | -| usdtBridge | - | -| tBTC | tBTC | +You can find the full code for the `MessageReceiver.sol` below. -### Wallet Set Up {: #wallet-connect-project-id } +??? code "MessageReceiver.sol" -When using Wormhole Connect, your selected blockchain network determines the available wallet options. + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; - - For EVM chains, wallets like MetaMask and WalletConnect are supported - - For Solana, you'll see options such as Phantom, Torus, and Coin98 +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol"; -The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. +contract MessageReceiver is IWormholeReceiver { + IWormholeRelayer public wormholeRelayer; + address public registrationOwner; -If you would like to offer WalletConnect as a supported wallet option, you'll need to obtain a project ID on the [WalletConnect cloud dashboard](https://cloud.walletconnect.com/){target=\_blank}. + // Mapping to store registered senders for each chain + mapping(uint16 => bytes32) public registeredSenders; -### Toggle Hamburger Menu {: #toggle-hamburger-menu } + event MessageReceived(string message); + event SourceChainLogged(uint16 sourceChain); -By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, causing the links to be positioned at the bottom. + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + registrationOwner = msg.sender; // Set contract deployer as the owner + } -#### Add Extra Menu Entry {: #add-extra-menu-entry } + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } -By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } -| Property | Description | -|:--------:|:-------------------------------------------:| -| `label` | Link name to show up | -| `href` | Target URL or URN | -| `target` | Anchor standard target, by default `_blank` | -| `order` | Order where the new item should be injected | + // Update receiveWormholeMessages to include the source address check + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 + ) public payable override isRegisteredSender(sourceChain, sourceAddress) { + require( + msg.sender == address(wormholeRelayer), + "Only the Wormhole relayer can call this function" + ); -#### Sample Configuration {: #sample-configuration } + // Decode the payload to extract the message + string memory message = abi.decode(payload, (string)); -```json -{ - "showHamburgerMenu": false, - "menu": [ - { - "label": "Advance Tools", - "href": "https://portalbridge.com", - "target": "_self", - "order": 1 + // Example use of sourceChain for logging + if (sourceChain != 0) { + emit SourceChainLogged(sourceChain); } - ] + + // Emit an event with the received message + emit MessageReceived(message); + } } -``` + ``` -### CoinGecko API Key {: #coingecko-api-key } +## Deploy Contracts -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. +This section will guide you through deploying the cross-chain messaging contracts on the Avalanche Fuji and Celo Alfajores Testnets. Follow these steps to get your contracts up and running. -### More Networks {: #more-networks } +### Deployment Tools +We use _Foundry_ to deploy our smart contracts. However, you can use any tool you're comfortable with, such as: -Specify a set of extra networks to be displayed on the network selection modal, each linking to a different page, dApp, or mobile app the user will be redirected to. The following properties are accessed through the `moreNetworks` property (e.g., `moreNetworks.href`): + - [Remix](https://remix.ethereum.org/){target=\_blank} for a browser-based IDE + - [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#installation){target=\_blank} for a more extensive JavaScript/TypeScript workflow + - [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for a CLI-focused experience with built-in scripting and testing features -|
    Property
    | Description | -|:--------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `href` | **Required**. Default value for missing network hrefs | -| `target` | Default value for missing network link targets. Defaults to `_self` | -| `description` | Brief description that should be displayed as a tooltip when the user hovers over a more network icon. Used as default for missing network descriptions | -| `networks[].icon` | **Required**. URL data encoded icon to display | -| `networks[].href` | Network href to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | -| `networks[].label` | **Required**. Display text | -| `networks[].name` | Unique network key. Defaults to a snake_case version of the label | -| `networks[].description` | Description value. Defaults to `moreNetworks.description` | -| `networks[].target` | href target value. Defaults to `moreNetworks.target` | -| `networks[].showOpenInNewIcon` | Disable top right open in new icon. Defaults to **true** if target is `_blank` or **false** if target is `_self` | +The contracts and deployment steps remain the same regardless of your preferred tool. The key is to ensure you have the necessary Testnet funds and are deploying to the right networks. -??? code "View full configuration" - ```json - { - ... - "moreNetworks": { - "href": "https://example.com", - "target": "_blank", - "description": "brief description that should be displayed as tooltip when the user hovers over a more network icon", - "networks": [ - { - "icon": "https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891", - "name": "more", - "label": "More networks", - "href": "https://portalbridge.com/#/transfer", - "showOpenInNewIcon": false - } - ] - } - ... -} - ``` +### Repository Setup -### More Tokens {: #more-tokens } +To get started with cross-chain messaging using Wormhole, first clone the [GitHub repository](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank}. This repository includes everything you need to deploy, interact, and test the message flow between chains. -Show a particular entry on the select tokens modal, redirecting the user to a different page, dApp, or mobile app. The following properties are accessed through the `moreTokens` property (e.g., `moreTokens.label`): +This demo focuses on using the scripts, so it's best to take a look at them, starting with `deploySender.ts`, `deployReceiver.ts`, and `sendMessage.ts`. -| Property | Description | -|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `label` | **Required**. Display text | -| `href` | **Required**. URL to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting | -| `target` | href target. Defaults to `_self` | +To configure the dependencies properly, run the following command: -### Explorer {: #explorer } +```bash +npm install +``` -Enable the explorer button to allow users to search for their transactions on a given explorer, filtering by their wallet address. The following properties are accessed through the `explorer` property (e.g., `explorer.label`): +The repository includes: -| Property | Description | -|:--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| -| `label` | Display text. Defaults to `Transactions` | -| `href` | **Required**. URL of the explorer, for instance [https://wormholescan.io/](https://wormholescan.io/){target=\_blank}. If present, the value `address` is replaced with the connected wallet address | -| `target` | `href` target. Defaults to `_blank` | ---- END CONTENT --- +- Two Solidity contracts: -Doc-Content: https://wormhole.com/docs/products/connect/configuration/data/ ---- BEGIN CONTENT --- ---- -title: Connect Data Configuration -description: Configure Wormhole Connect v1 (latest) with custom chains, tokens, routes, and more for enhanced blockchain interoperability. -categories: Connect, Transfer ---- + - **`MessageSender.sol`** - contract that sends the cross-chain message from Avalanche + - **`MessageReceiver.sol`** - contract that receives the cross-chain message on Celo -## Data Configuration +- Deployment scripts located in the `script` directory: -This page explains how to configure Wormhole Connect's core functionality, from choosing supported chains and tokens to bridging routes to setting up wallets and enabling price lookups. By the end, you'll know how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. + - **`deploySender.ts`** - deploys the `MessageSender` contract to Avalanche + - **`deployReceiver.ts`** - deploys the `MessageReceiver` contract to Celo + - **`sendMessage.ts`** - sends a message from Avalanche to Celo -## Get Started +- Configuration files and ABI JSON files for easy deployment and interaction: -Configure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop. + - **`chains.json`** - configuration file that stores key information for the supported Testnets, including the Wormhole relayer addresses, RPC URLs, and chain IDs. You likely won't need to modify this file unless you're working with different networks -=== "React integration" + - A dedicated `interfaces` directory inside the `src` folder for TypeScript type definitions: - ```ts - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + - **`ChainsConfig.ts`** - defines the types for the `chains.json` configuration file + - **`DeployedContracts.ts`** - contains types for deployed contract addresses and related information + - **`MessageJsons.ts`** - includes types for ABI and bytecode JSONs used by the deployment scripts + - **`index.ts`** - serves as an export aggregator for the interfaces, simplifying imports in other files -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - } -} +### Important Setup Steps - +1. **Add your private key** - create a `.env` file in the root of the project and add your private key: + + ```env + touch .env ``` -=== "Hosted integration" - - ```ts - import WormholeConnect, { - wormholeConnectHosted, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + Inside `.env`, add your private key in the following format: -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; + ```env + PRIVATE_KEY=INSERT_PRIVATE_KEY + ``` -const container = document.getElementById('bridge-container'); +2. **Compile the contracts** - ensure everything is set up correctly by compiling the contracts: -wormholeConnectHosted(container, { - config, -}); + ```bash + forge build ``` -!!! note - The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank}. - -## Examples {: #examples } +The expected output should be similar to this: -### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints } +
    +forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! + +
    -Connect lets you customize the available chains to match your project's needs. You should provide your own RPC endpoints, as the default public ones may not support essential functions like balance fetching. +### Deployment Process -=== "Mainnet" +Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the following key tasks: - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +1. **Load configuration and contract details** - each script begins by loading the necessary configuration details, such as the network's RPC URL and the contract's ABI and bytecode. This information is essential for deploying the contract to the correct blockchain network -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Polygon', 'Solana'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, -}; + === "`chains.json`" -function App() { - return ; + ```json + { + "chains": [ + { + "description": "Avalanche testnet fuji", + "chainId": 6, + "rpc": "https://api.avax-test.network/ext/bc/C/rpc", + "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", + "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", + "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" + }, + { + "description": "Celo Testnet", + "chainId": 14, + "rpc": "https://alfajores-forno.celo-testnet.org", + "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", + "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", + "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" + } + ] } - ``` + ``` -=== "Testnet" + === "`deploySender.ts`" - ```js - import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + ```typescript + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -const config: WormholeConnectConfig = { - // You can use Connect with testnet chains by specifying "network": - network: 'Testnet', - chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'], - rpcs: { - Avalanche: 'https://rpc.ankr.com/avalanche_fuji', - BaseSepolia: 'https://base-sepolia-rpc.publicnode.com', - }, -}; + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); + ``` -function App() { - return ; -} - ``` - -!!! note - For a complete list of available chain names, see the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank}. + === "`deployReceiver.ts`" -### Configuring Routes + ```typescript + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wrapped tokens) and Circle's CCTP (for native USDC). For most use cases, integrators require more than these default routes. The `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including default and third-party routes. + // Get the Celo Testnet configuration + const celoChain = chains.chains.find((chain) => + chain.description.includes('Celo Testnet') + ); + ``` -#### Available Route Plugins + !!! note + The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/contract-addresses/){target=\_blank}. -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: +2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol + === "`deploySender.ts`" -In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` -For further details on the `route` plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. + === "`deployReceiver.ts`" -#### Example: Offer Only CCTP Transfers + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +3. **Deploy the contract** - the contract is deployed to the network specified in the configuration. Upon successful deployment, the contract address is returned, which is crucial for interacting with the contract later on -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + === "`deploySender.ts`" -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; + ```typescript + avalancheChain.wormholeRelayer + ); + await senderContract.waitForDeployment(); + ``` -; -``` + === "`deployReceiver.ts`" -#### Example: Offer All Default Routes and Third-Party Plugins + ```typescript + celoChain.wormholeRelayer + ); + await receiverContract.waitForDeployment(); + ``` -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +4. **Register the `MessageSender` on the target chain** - after you deploy the `MessageReceiver` contract on the Celo Alfajores network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract -import { myNttConfig } from './consts'; // Custom NTT configuration + ```typescript + const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; + if (!avalancheSenderAddress) { + throw new Error('Avalanche MessageSender address not found.'); + } -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; + // Define the source chain ID for Avalanche Fuji + const sourceChainId = 6; -; -``` + // Call setRegisteredSender on the MessageReceiver contract + const tx = await (receiverContract as any).setRegisteredSender( + sourceChainId, + ethers.zeroPadValue(avalancheSenderAddress, 32) + ); + await tx.wait(); + ``` -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. +You can find the full code for the `deploySender.ts` and `deployReceiver.ts` below. -### Adding Custom Tokens {: #custom-tokens } +??? code "deploySender.ts" -The following section shows how to add an arbitrary token to your deployment of Connect. + ```typescript + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { + ChainsConfig, + DeployedContracts, + MessageSenderJson, +} from './interfaces'; -!!! note - You will need to [register](https://portalbridge.com/advanced-tools/#/register){target=\_blank} your token with the Token Bridge to get the contract addresses necessary for it to work with that protocol. +dotenv.config(); -This example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with the Token Bridge. +async function main(): Promise { + // Load the chain configuration from JSON + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -See the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/types.ts){target=\_blank} for the type definition of `TokensConfig`. + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); + if (!avalancheChain) { + throw new Error( + 'Avalanche testnet configuration not found in chains.json.' + ); + } -```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); -const config: WormholeConnectConfig = { - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - nativeChain: 'Ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - coinGeckoId: 'bonk', - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; -``` + // Load the ABI and bytecode of the MessageSender contract + const messageSenderJson: MessageSenderJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); -### Whitelisting Tokens {: #whitelisting-tokens } + const { abi, bytecode } = messageSenderJson; -Connect offers a list of built-in tokens by default. You can see it below: + // Create a ContractFactory for MessageSender + const MessageSender = new ethers.ContractFactory(abi, bytecode, wallet); -- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/mainnet/tokens.ts){target=\_blank} -- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/development/wormhole-connect/src/config/testnet/tokens.ts){target=\_blank} + // Deploy the contract using the Wormhole Relayer address for Avalanche Fuji + const senderContract = await MessageSender.deploy( + avalancheChain.wormholeRelayer + ); + await senderContract.waitForDeployment(); -You can customize the tokens shown in the UI using the `tokens` property. The following example adds a custom token and limits Connect to showing only that token, along with the native gas tokens ETH and SOL. + console.log('MessageSender deployed to:', senderContract.target); // `target` is the address in ethers.js v6 -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + // Update the deployedContracts.json file + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/deployedContracts.json' + ); + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: ['ETH', 'SOL', 'BONK'], - rpcs: { - Ethereum: 'https://rpc.ankr.com/eth', - Solana: 'https://rpc.ankr.com/solana', - }, - tokensConfig: { - BONK: { - key: 'BONK', - symbol: 'BONK', - icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587', - tokenId: { - chain: 'Ethereum', - address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6', - }, - decimals: 18, - }, - }, - wrappedTokens: { - BONK: { - Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - }, - }, -}; + deployedContracts.avalanche = { + MessageSender: senderContract.target as any, + deployedAt: new Date().toISOString(), + }; -function App() { - return ; + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); } -``` -You can whitelist tokens by symbol or by specifying tuples of [chain, address]. For example, this would show only BONK token (on all chains you've whitelisted) as well as [`EPjFW...TDt1v`](https://solscan.io/token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v){target=\_blank} on Solana, which is USDC. +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +??? code "deployReceiver.ts" -const config: WormholeConnectConfig = { - chains: ['Ethereum', 'Solana'], - tokens: [ - // Whitelist BONK on every whitelisted chain - 'BONK', - // Also whitelist USDC, specifically on Solana - ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'] - ], - ... -}; + ```typescript + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { + ChainsConfig, + DeployedContracts, + MessageReceiverJson, +} from './interfaces'; -function App() { - return ; -} -``` +dotenv.config(); -### User-Inputted Tokens {: #user-inputted-tokens } +async function main(): Promise { + // Load the chain configuration from the JSON file + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -As of version 2.0, Connect allows users to paste token addresses to bridge any token they want. As an integrator, you may want to disable this feature if you are deploying Connect for use only with a specific token(s). + // Get the Celo Testnet configuration + const celoChain = chains.chains.find((chain) => + chain.description.includes('Celo Testnet') + ); + if (!celoChain) { + throw new Error('Celo Testnet configuration not found.'); + } -If you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this: + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(celoChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + // Load the ABI and bytecode of the MessageReceiver contract + const messageReceiverJson: MessageReceiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/MessageReceiver.sol/MessageReceiver.json' + ), + 'utf8' + ) + ); -const config: WormholeConnectConfig = { - ui: { - disableUserInputtedTokens: true - } -}; + const { abi, bytecode } = messageReceiverJson; -function App() { - return ; -} -``` + // Create a ContractFactory for MessageReceiver + const MessageReceiver = new ethers.ContractFactory(abi, bytecode, wallet); -Setting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses. + // Deploy the contract using the Wormhole Relayer address for Celo Testnet + const receiverContract = await MessageReceiver.deploy( + celoChain.wormholeRelayer + ); + await receiverContract.waitForDeployment(); -### Transaction Settings {: #transaction-settings } + console.log('MessageReceiver deployed to:', receiverContract.target); // `target` is the contract address in ethers.js v6 -Landing transactions on Solana can require finely tuned priority fees when there is congestion. You can tweak how Connect determines these with `transactionSettings`. All of the parameters in this configuration are optional; you can provide any combination of them. + // Update the deployedContracts.json file + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/deployedContracts.json' + ); + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + // Retrieve the address of the MessageSender from the deployedContracts.json file + const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; + if (!avalancheSenderAddress) { + throw new Error('Avalanche MessageSender address not found.'); + } -const config: WormholeConnectConfig = { - transactionSettings: { - Solana: { - priorityFee: { - // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees. - // For example, you can set percentile to 0.95 to make Connect compute the - // 95th percentile priority fee amount based on recent transactions - percentile: 0.95, + // Define the source chain ID for Avalanche Fuji + const sourceChainId = 6; - // Any number, defaults to 1.0. The fee amount is multiplied by this number. - // This can be used to further raise or lower the fees Connect is using. - // For example, percentile=0.95 and percentileMultiple=1.1 would use - // the 95th percentile fee, with a 10% increase - percentileMultiple: 1.1, + // Call setRegisteredSender on the MessageReceiver contract + const tx = await (receiverContract as any).setRegisteredSender( + sourceChainId, + ethers.zeroPadValue(avalancheSenderAddress, 32) + ); + await tx.wait(); - // Minimum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 1 - min: 200_000, + console.log( + `Registered MessageSender (${avalancheSenderAddress}) for Avalanche chain (${sourceChainId})` + ); - // Maximum fee you want to use in microlamports, regardless of recent transactions - // Defaults to 100,000,000 - max: 5_000_000, - } - } - } -}; + deployedContracts.celo = { + MessageReceiver: receiverContract.target as any, + deployedAt: new Date().toISOString(), + }; -function App() { - return ; + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); } -``` -!!! note - Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\_blank} RPC endpoint. +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` -### Wallet Set Up {: #reown-cloud-project-id } +### Deploy the Sender Contract -Your selected blockchain network determines the available wallet options when using Wormhole Connect. +The sender contract will handle quoting and sending messages cross-chain. - - For EVM chains, wallets like MetaMask and Reown Cloud (formerly WalletConnect) are supported - - For Solana, you'll see options such as Phantom, Torus, and Coin98 +1. Run the following command to deploy the sender contract: -The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. + ```bash + npm run deploy:sender + ``` -If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. +2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\_blank} -### CoinGecko API Key {: #coingecko-api-key } +
    +npm run deploy:sender + > wormhole-cross-chain@1.0.0 deploy:sender + > node script/deploySender.ts + MessageSender deployed to: 0xf5c474f335fFf617fA6FD04DCBb17E20ee0cEfb1 + +
    -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +### Deploy the Receiver Contract -const config: WormholeConnectConfig = { - coinGeckoApiKey: 'INSERT_API_KEY', -}; +The receiver contract listens for cross-chain messages and logs them when received. -function App() { - return ; -} -``` ---- END CONTENT --- +1. Deploy the receiver contract with this command: + + ```bash + npm run deploy:receiver + ``` -Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ ---- BEGIN CONTENT --- ---- -title: Connect Theme & UI Customization -description: Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. -categories: Connect, Transfer ---- +2. After deployment, note down the contract address. You may check the contract on the [Celo Alfajores Explorer](https://alfajores.celoscan.io/){target=\_blank}. -## Theme & UI Customization -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +## Send a Cross-Chain Message -### Changing the Color Scheme +Now that both the sender and receiver contracts are deployed, let's move on to the next exciting step: sending a cross-chain message from Avalanche Fuji to Celo Alfajores. -You can customize Connect's color scheme by providing a `theme` prop. +In this example, we will use the `sendMessage.ts` script to transmit a message from the sender contract on Avalanche to the receiver contract on Celo. The script uses [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} to interact with the deployed contracts, calculate the cross-chain cost dynamically, and handle the transaction. -=== "React integration" +Let's break down the script step by step. - ```ts - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, -} from '@wormhole-foundation/wormhole-connect'; +1. **Load configuration files** -const config: WormholeConnectConfig = { - /* Your config... */ -}; + 1. **`chains.json`** - contains details about the supported Testnet chains, such as RPC URLs and relayer addresses + 2. **`deployedContracts.json`** - stores the addresses of the deployed sender and receiver contracts. This file is dynamically updated when contracts are deployed, but users can also manually add their own deployed contract addresses if needed -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; + ```typescript + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -function App() { - return ; -} + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/deployedContracts.json'), + 'utf8' + ) + ); ``` -=== "Hosted integration" +2. **Configure the provider and signer** - the script first reads the chain configurations and extracts the contract addresses. One essential step in interacting with a blockchain is setting up a _provider_. A provider is your connection to the blockchain network. It allows your script to interact with the blockchain, retrieve data, and send transactions. In this case, we're using a JSON-RPC provider - ```ts - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - wormholeConnectHosted, -} from '@wormhole-foundation/wormhole-connect'; + Next, we configure the wallet, which will be used to sign transactions. The wallet is created using the private key and the provider. This ensures that all transactions sent from this wallet are broadcast to the Avalanche Fuji network: + + ```typescript + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + ``` -const config: WormholeConnectConfig = { - /* Your config... */ -}; + After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it: -const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - font: 'Comic Sans; sans-serif', -}; - -const container = document.getElementById('bridge-container'); - -wormholeConnectHosted(container, { - config, - theme, -}); + ```typescript + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); ``` -The `WormholeConnectTheme` type supports the following properties: +3. **Set up the message details** - the next part of the script defines the target chain (Celo) and the target address (the receiver contract on Celo): -|
    Property
    | Description | Example | -|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:| -| `mode` | Dark mode or light mode. **Required** | `"dark"` or `"light"` | -| `input` | Color used for input fields, dropdowns | `"#AABBCC"` | -| `primary` | Primary color used for buttons | `"#AABBCC"` | -| `secondary` | Secondary color used for some UI elements | `"#AABBCC"` | -| `text` | Primary color used for text | `"#AABBCC"` | -| `textSecondary` | Secondary color used for dimmer text | `"#AABBCC"` | -| `error` | Color to display errors in, usually some shade of red | `"#AABBCC"` | -| `success` | Color to display success messages in | `"#AABBCC"` | -| `font` | Font used in the UI, can be custom font available in your application | `"Arial; sans-serif"` | + ```typescript + const targetAddress = deployedContracts.celo.MessageReceiver; + ``` -### Toggle Hamburger Menu {: #toggle-hamburger-menu } + You can customize the message that will be sent across chains: -By setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom. + ```typescript + + ``` -#### Add Extra Menu Entry {: #add-extra-menu-entry } +4. **Estimate cross-chain cost** - before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function: -By setting the `showHamburgerMenu` option to `false,` you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`): + ```typescript + + ``` -| Property | Description | -|:--------:|:-------------------------------------------:| -| `label` | Link name to show up | -| `href` | Target URL or URN | -| `target` | Anchor standard target, by default `_blank` | -| `order` | Order where the new item should be injected | + This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message. -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +5. **Send a message** - with everything set up, the message is sent using the `sendMessage` function: -const config: WormholeConnectConfig = { - ui: { - showHamburgerMenu: false, - menu: [ - { - label: 'Advance Tools', - href: 'https://portalbridge.com', - target: '_self', - order: 1, - }, - ], - }, -}; + ```typescript + targetChain, + targetAddress, + message, + { + value: txCost, + } + ); + ``` -function App() { - return ; -} -``` ---- END CONTENT --- + After sending, the script waits for the transaction to be confirmed: -Doc-Content: https://wormhole.com/docs/products/connect/faqs/ ---- BEGIN CONTENT --- ---- -title: Connect FAQs -description: Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. -categories: Connect, Transfer ---- + ```typescript + + ``` -# Wormhole Connect FAQs +6. **Run the script** - to send the message, run the following command: -## What types of assets does Connect support? + ```bash + npm run send:message + ``` -Connect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes: +If everything is set up correctly, the message will be sent from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. You can monitor the transaction and verify that the message was received on Celo using the [Wormhole Explorer](https://wormholescan.io/#/?network=TESTNET){target=\_blank}. - - Major stablecoins like USDT and USDC (via CCTP) - - Native gas tokens such as ETH, SOL, etc. - - Cross-chain asset swaps through integrators like Mayan +The console should output something similar to this: -When bridging assets through the Wormhole Token Bridge, depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain. +
    +npm run send:message + > wormhole-cross-chain@1.0.0 send:message + > node script/sendMessage.ts +Sender Contract Address: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 +Receiver Contract Address: 0x692550997C252cC5044742D1A2BD91E4f4b46D39 +... +Transaction sent, waiting for confirmation... +... +Message sent! Transaction hash: + 0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6 +You may see the transaction status on the Wormhole Explorer: + https://wormholescan.io/#/tx/0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6?network=TESTNET + +
    -## What chains does Connect support? +You can find the full code for the `sendMessage.ts` below. -Connect supports around 30 chains, spanning various blockchain runtimes: +??? code "sendMessage.ts" - - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.) - - Solana - - Move-based chains (Sui, Aptos) + ```solidity + import { ethers } from 'ethers'; +import fs from 'fs'; +import path from 'path'; +import dotenv from 'dotenv'; +import { ChainsConfig, DeployedContracts } from './interfaces'; -For a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\_blank}. +dotenv.config(); -## What is gas dropoff? +async function main(): Promise { + // Load the chain configuration and deployed contract addresses + const chains: ChainsConfig = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/chains.json'), + 'utf8' + ) + ); -Gas dropoff allows users to receive gas for transaction fees on the destination chain, eliminating the need to acquire the native gas token from a centralized exchange. The relayer automatically swaps part of the transferred assets into the native gas token, enabling seamless entry into new ecosystems. + const deployedContracts: DeployedContracts = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../deploy-config/deployedContracts.json'), + 'utf8' + ) + ); -## Can I customize Connect inside my application? + console.log( + 'Sender Contract Address: ', + deployedContracts.avalanche.MessageSender + ); + console.log( + 'Receiver Contract Address: ', + deployedContracts.celo.MessageReceiver + ); + console.log('...'); -Connect can be [fully customized](https://connect-in-style.wormhole.com/){target=\_blank} to choose the chains and assets you wish to support. You may also select different themes and colors to tailor Connect for your decentralized application. For details, see the [GitHub readme](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}. + // Get the Avalanche Fuji configuration + const avalancheChain = chains.chains.find((chain) => + chain.description.includes('Avalanche testnet') + ); -## Which functions or events does Connect rely on for NTT integration? + if (!avalancheChain) { + throw new Error( + 'Avalanche testnet configuration not found in chains.json.' + ); + } -Connect relies on the NTT SDK for integration, with platform-specific implementations for Solana and EVM. The critical methods involved include initiate and redeem functions and rate capacity methods. These functions ensure Connect can handle token transfers and manage chain-rate limits. + // Set up the provider and wallet + const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); -## Do integrators need to enable wallets like Phantom or Backpack in Connect? + // Load the ABI of the MessageSender contract + const messageSenderJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), + 'utf8' + ) + ); -Integrators don’t need to explicitly enable wallets like Phantom or Backpack in Connect. However, the wallet must be installed and enabled in the user's browser to appear as an option in the interface. + const abi = messageSenderJson.abi; -## Which function should be modified to set priority fees for Solana transactions? + // Create a contract instance for MessageSender + const MessageSender = new ethers.Contract( + deployedContracts.avalanche.MessageSender, // Automatically use the deployed address + abi, + wallet + ); -In [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank}, you can modify the priority fees for Solana transactions by updating the `computeBudget/index.ts` file. This file contains the logic for adjusting the compute unit limit and priority fees associated with Solana transactions. + // Define the target chain and target address (the Celo receiver contract) + const targetChain = 14; // Wormhole chain ID for Celo Alfajores + const targetAddress = deployedContracts.celo.MessageReceiver; -To control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions. + // The message you want to send + const message = 'Hello from Avalanche to Celo!'; -The relevant file can be found in the Connect codebase: [`computeBudget/index.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/62f1ba8ee5502ac6fd405680e6b3816c9aa54325/sdk/src/contexts/solana/utils/computeBudget/index.ts){target=\_blank}. + // Dynamically quote the cross-chain cost + const txCost = await MessageSender.quoteCrossChainCost(targetChain); -## Is there a minimum amount for bridging with CCTP or the Connect SDK? + // Send the message (make sure to send enough gas in the transaction) + const tx = await MessageSender.sendMessage( + targetChain, + targetAddress, + message, + { + value: txCost, + } + ); -There is no minimum amount for bridging via CCTP if the user covers the gas fees on both the source and destination chains. However, if the transfer is automatically relayed, a minimum amount is required to cover relay fees on the destination chain. The relay provider charges these fees at cost. + console.log('Transaction sent, waiting for confirmation...'); + await tx.wait(); + console.log('...'); -Current relay fees: + console.log('Message sent! Transaction hash:', tx.hash); + console.log( + `You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/${tx.hash}?network=TESTNET` + ); +} -- Ethereum L1: ~4.2 USDC -- Base, Optimism, Arbitrum, Avalanche: 0.3 USDC +main().catch((error) => { + console.error(error); + process.exit(1); +}); + + ``` -Additional notes: +## Conclusion -- **USDC to Solana** - Wormhole's native CCTP route does not currently support automatic relaying of USDC to Solana. However, you can transfer USDC to Solana using the [Mayan plugin](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} for the SDK. Mayan is a protocol that integrates Wormhole and CCTP to enable this functionality -- **Frontend integrations** - - **Connect** - A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank} - - **TypeScript SDK** - A lower-level integration option, available via [@wormhole-foundation/sdk](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}, allowing developers to build custom UIs +You're now fully equipped to build cross-chain contracts using the Wormhole protocol! With this tutorial, you've learned how to: - !!!note - The TypeScript SDK was previously referred to as the "Connect SDK," but this naming has since been discontinued. +- Deploy sender and receiver contracts on different Testnets +- Send a cross-chain message from one blockchain to another +- Monitor the status of your cross-chain transactions using the Wormhole Explorer and Wormhole-Solidity-SDK --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/connect/get-started/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-token-contracts/ --- BEGIN CONTENT --- --- -title: Get Started with Connect -description: Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. -categories: Connect, Transfer +title: Cross-Chain Token Transfers +description: Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. --- -# Get Started with Connect +# Create Cross-Chain Token Transfer Contracts -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} ## Introduction -Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. +In this tutorial, you'll learn how to create a simple cross-chain token transfer system using the Wormhole protocol via the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. We'll guide you through building and deploying smart contracts that enable seamless token transfers of IERC-20 tokens between blockchains. Whether you're a developer looking to explore cross-chain applications or just interested in the Wormhole protocol, this guide will help you understand the fundamentals. -## Prerequisites +By the end of this tutorial, you'll have a working cross-chain token transfer system built with the powerful tools provided by the Wormhole Solidity SDK, which you can further customize and integrate into your projects. -Before you begin, make sure you have the following: +## Prerequisites -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +Before you begin, ensure you have the following: -- (Optional) To test a transfer from your demo app, you'll need: +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts +- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees +- [USDC Testnet](https://faucet.circle.com/){target=\_blank} tokens on Avalanche-Fuji or/and Celo-Alfajores for cross-chain transfer +- Wallet private key - - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} - - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) +## Valid Tokens for Transfer -## Install and Setup Project +It's important to note that this tutorial leverages [Wormhole's TokenBridge](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/TokenBridge.sol){target=\_blank} to transfer tokens between chains. So, the tokens you'd like to transfer must have an attestation on the `TokenBridge` contract of the target blockchain. -1. Clone the demo repository and navigate to the project directory: +To simplify this process, we've included a tool for verifying if a token has an attestation on the target chain. This tool uses the [`wrappedAsset`](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/BridgeGetters.sol#L50-L52){target=\_blank} function from the `TokenBridge` contract. If the token has an attestation, the `wrappedAsset` function returns the address of the wrapped token on the target chain; otherwise, it returns the zero address. + +???- tip "Check Token Attestation" + 1. Clone the [repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} and navigate to the project directory: + ```bash + git clone https://github.com/wormhole-foundation/demo-cross-chain-token-transfer.git + cd cross-chain-token-transfers + ``` + 2. Install the dependencies: + ```bash + npm install + ``` + + 3. Run the script to check token attestation: + ```bash + npm run verify + ``` + + 4. Follow the prompts: + + 1. Enter the RPC URL of the target chain + 2. Enter the `TokenBridge` contract address on the target chain + 3. Enter the token contract address on the source chain + 4. Enter the source chain ID + + 5. The expected output when the token has an attestation: + +
    +npm run verify + > cross-chain-token-transfer@1.0.0 verify + > npx ts-node script/check-attestation.ts + + Enter the TARGET chain RPC URL: https://alfajores-forno.celo-testnet.org + Enter the Token Bridge contract address on the TARGET chain: 0x05...E153 + Enter the token contract address on the SOURCE chain: 0x54...bc65 + Enter the SOURCE chain ID: 6 + The token is attested on the target chain. Wrapped token address: 0xDDB349c976cA2C873644F21f594767Eb5390C831 + +
    + + Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process. + +## Project Setup + +Let's start by initializing a new Foundry project. This will set up a basic structure for our smart contracts. +1. Open your terminal and run the following command to initialize a new Foundry project: + ```bash - git clone https://github.com/wormhole-foundation/demo-basic-connect.git - cd demo-basic-connect + forge init cross-chain-token-transfers ``` -2. Install the dependencies: + This will create a new directory named `cross-chain-token-transfers` with a basic project structure. This also initializes a new `git` repository. + +2. Navigate into the newly created project directory: ```bash - npm install + cd cross-chain-token-transfers ``` -3. Start the application: +3. Install the Wormhole Solidity SDK: ```bash - npm start + forge install wormhole-foundation/wormhole-solidity-sdk ``` -4. Open your browser to [localhost:3000](http://localhost:3000){target=\_blank} to view the application locally. It will look similar to the following: + To ease development, we'll use the Wormhole Solidity SDK, which provides useful helpers for cross-chain development. + This SDK includes the `TokenSender` and `TokenReceiver` abstract classes, which simplify sending and receiving tokens across chains. - ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp) +## Build Cross-Chain Contracts -## Configure Connect +In this section, we'll build two smart contracts to send tokens from a source chain and receive them on a target chain. These contracts will interact with the Wormhole protocol to facilitate secure and seamless cross-chain token transfers. -Open the `App.tsx` file in your code editor of choice. You will see code similar to the following: +At a high level, our contracts will: -```typescript title="App.tsx" -import './App.css'; -import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, -} from '@wormhole-foundation/wormhole-connect'; +1. Send tokens from one blockchain to another using the Wormhole protocol +2. Receive and process the tokens on the target chain, ensuring they are correctly transferred to the intended recipient -function App() { - const config: WormholeConnectConfig = { - // Define the network - network: 'Testnet', +Before diving into the contract implementation steps, let’s first break down the key parts of the contracts. - // Define the chains - chains: ['Sui', 'Avalanche'], +### Sender Contract: CrossChainSender - // UI configuration - ui: { - title: 'SUI Connect TS Demo', - }, - }; +The `CrossChainSender` contract calculates the cost of sending tokens across chains and then facilitates the actual token transfer. - const theme: WormholeConnectTheme = { - // Define the theme - mode: 'dark', - primary: '#78c4b6', - }; +Let's start writing the `CrossChainSender` contract: - return ; -} +1. Create a new file named `CrossChainSender.sol` in the `/src` directory: + + ```bash + touch src/CrossChainSender.sol + ``` -export default App; -``` +2. Open the file. First, we'll start with the imports and the contract setup: -The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: + ```solidity + pragma solidity ^0.8.13; -- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` -- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains -- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI -- **Defines the theme** - this example sets the mode to `dark` and adds a primary color +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; -## Interact with Connect +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; -Congratulations! You've successfully used Connect to create a simple multichain token transfer application. You can now follow the prompts in the UI to connect your developer wallets and send a test transfer. + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + + ``` -## Next Steps + This sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. -For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. + With the contract structure in place, define the following functions within its body to enable multichain token transfers. -For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. +3. Next, let's add a function that estimates the cost of sending tokens across chains: - ---- END CONTENT --- + ```solidity + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); -Doc-Content: https://wormhole.com/docs/products/connect/guides/upgrade/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect v1.0 Migration Guide -description: Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. -categories: Connect, Transfer ---- + cost = deliveryCost + wormhole.messageFee(); + } + ``` -# Wormhole Connect v1.0 Migration Guide + This function, `quoteCrossChainDeposit`, helps calculate the cost of transferring tokens to a different chain. It factors in the delivery cost and the cost of publishing a message via the Wormhole protocol. -## Overview +4. Finally, we'll add the function that sends the tokens across chains: -The Wormhole Connect feature has been updated to **version 1.0**, introducing a modernized design and improved routing for faster native-to-native token transfers. This stable release comes with several breaking changes in how to configure the application, requiring minor updates to your integration. + ```solidity + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); -This guide will help you migrate to the new version in just a few simple steps. By following this migration guide, you'll learn how to: + IERC20(token).transferFrom(msg.sender, address(this), amount); - - Update to the latest Connect package - - Apply configuration changes to the **`WormholeConnectConfig`** object - - Understand new routing capabilities and plugin options + bytes memory payload = abi.encode(recipient); -These updates ensure better performance and a smoother integration experience. + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } + ``` -## Update the Connect Package + This `sendCrossChainDeposit` function is where the actual token transfer happens. It sends the tokens to the recipient on the target chain using the Wormhole protocol. -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +Here’s a breakdown of what happens in each step of the `sendCrossChainDeposit` function: -Run the following command in your terminal: +1. **Cost calculation** - the function starts by calculating the cost of the cross-chain transfer using `quoteCrossChainDeposit`(`targetChain`). This cost includes both the delivery fee and the Wormhole message fee. The `sendCrossChainDeposit` function then checks that the user has sent the correct amount of Ether to cover this cost (`msg.value`) -```bash -npm install @wormhole-foundation/wormhole-connect@^1.0 -``` +2. **Token transfer to contract** - the next step is to transfer the specified amount of tokens from the user to the contract itself using `IERC-20(token).transferFrom(msg.sender, address(this), amount)`. This ensures that the contract has custody of the tokens before initiating the cross-chain transfer -This command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes. +3. **Payload encoding** - The recipient's address on the target chain is encoded into a payload using `abi.encode(recipient)`. This payload will be sent along with the token transfer, so the target contract knows who should receive the tokens on the destination chain -## Update the `WormholeConnectConfig` Object +4. **Cross-chain transfer** - the `sendTokenWithPayloadToEvm` function is called to initiate the cross-chain token transfer. This function: + - Specifies the `targetChain` (the Wormhole chain ID of the destination blockchain). + - Sends the `targetReceiver` contract address on the target chain that will receive the tokens. + - Attaches the payload containing the recipient's address. + - Sets the `GAS_LIMIT` for the transaction. + - Passes the token `address` and `amount` to transfer. -In version 1.0, the `WormholeConnectConfig` object underwent several breaking changes. Most of these changes are minor and can be applied quickly. Below is a summary of the key changes, followed by detailed examples. + This triggers the Wormhole protocol to handle the cross-chain messaging and token transfer, ensuring the tokens and payload reach the correct destination on the target chain. -### Summary of Breaking Changes +You can find the complete code for the `CrossChainSender.sol` below. -- Chain names are now capitalized: `solana` → `Solana` -- `env` renamed to `network` and is now capitalized: `mainnet` → `Mainnet` -- `networks` renamed to `chains`, with capitalized names -- `routes` updated to use route plugins -- `nttGroups` removed in favor of route plugin configuration -- `tokensConfig` updated, with a new key `wrappedTokens` added -- Many UI-related properties consolidated under a top-level `ui` key -- `customTheme` and `mode` were removed, replaced by a top-level `theme` property +??? code "MessageSender.sol" -These changes are explained in more detail below, with examples for easy reference. + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; -### Capitalize Chain Names +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; -In version 1.0, chain names are now consistent with the `Chain` type from the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, and must be capitalized. This affects all config properties where a chain is referenced, including `rpcs`, `rest`, `graphql`, and `chains`. +contract CrossChainSender is TokenSender { + uint256 constant GAS_LIMIT = 250_000; -=== "v0.x" + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - ethereum: 'INSERT_ETH_RPC_URL', - solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` -=== "v1.x" - - ```typescript - const config: WormholeConnectConfig = { - rpcs: { - Ethereum: 'INSERT_ETH_RPC_URL', - Solana: 'INSERT_SOLANA_RPC_URL', - }, - }; - ``` + // Function to get the estimated cost for cross-chain deposit + function quoteCrossChainDeposit( + uint16 targetChain + ) public view returns (uint256 cost) { + uint256 deliveryCost; + (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( + targetChain, + 0, + GAS_LIMIT + ); -You can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/fa4ba4bc349a7caada809f209090d79a3c5962fe/core/base/src/constants/chains.ts#L12-L66){target=\_blank}. + cost = deliveryCost + wormhole.messageFee(); + } -### Rename `env` to `network` + // Function to send tokens and payload across chains + function sendCrossChainDeposit( + uint16 targetChain, + address targetReceiver, + address recipient, + uint256 amount, + address token + ) public payable { + uint256 cost = quoteCrossChainDeposit(targetChain); + require( + msg.value == cost, + "msg.value must equal quoteCrossChainDeposit(targetChain)" + ); -The `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments. + IERC20(token).transferFrom(msg.sender, address(this), amount); -=== "v0.x" + bytes memory payload = abi.encode(recipient); - ```typescript - const config: WormholeConnectConfig = { - env: 'testnet', - }; + sendTokenWithPayloadToEvm( + targetChain, + targetReceiver, + payload, + 0, + GAS_LIMIT, + token, + amount + ); + } +} ``` -=== "v1.x" - ```typescript - const config: WormholeConnectConfig = { - network: 'Testnet', - }; - ``` +### Receiver Contract: CrossChainReceiver -If you don’t explicitly set the `network` value, Connect will default to `Mainnet`. +The `CrossChainReceiver` contract is designed to handle the receipt of tokens and payloads from another blockchain. It ensures that the tokens are correctly transferred to the designated recipient on the receiving chain. -```typescript -// Defaults to Mainnet -const config: WormholeConnectConfig = {}; -``` +Let's start writing the `CrossChainReceiver` contract: -For more information, refer to the [network constants list](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/networks.ts){target=\_blank}. +1. Create a new file named `CrossChainReceiver.sol` in the `/src` directory: -### Rename `networks` to `chains` + ```bash + touch src/CrossChainReceiver.sol + ``` -The `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized. +2. Open the file. First, we'll start with the imports and the contract setup: -=== "v0.x" + ```solidity + pragma solidity ^0.8.13; - ```typescript - const config: WormholeConnectConfig = { - networks: ['solana', 'ethereum'], - }; - ``` -=== "v1.x" +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; - ```typescript - const config: WormholeConnectConfig = { - chains: ['Solana', 'Ethereum'], - }; +contract CrossChainReceiver is TokenReceiver { + // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract + + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} + ``` -### Update `routes` to Use Route Plugins + Similar to the `CrossChainSender` contract, this sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +3. Next, let's add a function inside the contract to handle receiving the payload and tokens: -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: + ```solidity + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + require(receivedTokens.length == 1, "Expected 1 token transfer"); - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); -For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } + ``` -#### Available `route` Plugins + This `receivePayloadAndTokens` function processes the tokens and payload sent from another chain, decodes the recipient address, and transfers the tokens to them using the Wormhole protocol. This function also validates the emitter (`sourceAddress`) to ensure the message comes from a trusted sender. -The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: + This function ensures that: -???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route - - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - - **`CCTPRoute`** - manually redeemed CCTP route - - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route - - **`DEFAULT_ROUTES`** - array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute) - - **`nttAutomaticRoute(nttConfig)`** - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route - - **`nttManualRoute(nttConfig)`** - function that returns the manually-redeemed NTT route - - **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array - - **`MayanRoute`** - route that offers multiple Mayan protocols - - **`MayanRouteSWIFT`** - route for Mayan’s Swift protocol only - - **`MayanRouteMCTP`** - route for Mayan’s MCTP protocol only - - **`MayanRouteWH`** - route for Mayan’s original Wormhole transfer protocol + - It only processes one token transfer at a time + - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract + - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface -In addition to these routes, developers can create custom routes for their own Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. +After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. -For further details on the Route plugin interface, refer to the [Wormhole TypeScript SDK route code](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/route.ts){target=\_blank}. +??? tip "Understanding the `TokenReceived` Struct" -Now that you know the available `route` plugins, let's explore some examples of configuring them. + Let’s delve into the fields provided to us in the `TokenReceived` struct: -#### Example: Offer Only CCTP Transfers + ```solidity + struct TokenReceived { + bytes32 tokenHomeAddress; + uint16 tokenHomeChain; + address tokenAddress; + uint256 amount; + uint256 amountNormalized; +} + ``` -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: + - **`tokenHomeAddress`** - the original address of the token on its native chain. This is the same as the token field in the call to `sendTokenWithPayloadToEvm` unless the original token sent is a Wormhole-wrapped token. In that case, this will be the address of the original version of the token (on its native chain) in Wormhole address format (left-padded with 12 zeros) -```typescript -import WormholeConnect, { - AutomaticCCTPRoute, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; + - **`tokenHomeChain`** - the Wormhole chain ID corresponding to the home address above. This will typically be the source chain unless the original token sent is a Wormhole-wrapped asset, which will be the chain of the unwrapped version of the token -const config: WormholeConnectConfig = { - routes: [AutomaticCCTPRoute], -}; + - **`tokenAddress`** - the address of the IERC-20 token on the target chain that has been transferred to this contract. If `tokenHomeChain` equals the target chain, this will be the same as `tokenHomeAddress`; otherwise, it will be the Wormhole-wrapped version of the token sent -; -``` + - **`amount`** - the token amount sent to you with the same units as the original token. Since `TokenBridge` only sends with eight decimals of precision, if your token has 18 decimals, this will be the "amount" you sent, rounded down to the nearest multiple of 10^10 -#### Example: Offer All Default Routes and Third-Party Plugins + - **`amountNormalized`** - the amount of token divided by (1 if decimals ≤ 8, else 10^(decimals - 8)) -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +You can find the complete code for the `CrossChainReceiver.sol` contract below: -```typescript -import WormholeConnect, { - DEFAULT_ROUTES, - nttRoutes, - MayanRouteSWIFT, - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +??? code "CrossChainReceiver.sol" -import { myNttConfig } from './consts'; // Custom NTT configuration + ```solidity + // SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; -const config: WormholeConnectConfig = { - routes: [...DEFAULT_ROUTES, ...nttRoutes(myNttConfig), MayanRouteSWIFT], -}; +import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; +import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; -; -``` +contract CrossChainReceiver is TokenReceiver { + // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract -This flexible plugin allows you to combine default routes (such as Token Bridge and CCTP) with third-party protocols, offering complete control over which routes are available in your application. + constructor( + address _wormholeRelayer, + address _tokenBridge, + address _wormhole + ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} -### Update the `tokensConfig` Structure + // Function to receive the cross-chain payload and tokens with emitter validation + function receivePayloadAndTokens( + bytes memory payload, + TokenReceived[] memory receivedTokens, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 // deliveryHash + ) + internal + override + onlyWormholeRelayer + isRegisteredSender(sourceChain, sourceAddress) + { + require(receivedTokens.length == 1, "Expected 1 token transfer"); -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. + // Decode the recipient address from the payload + address recipient = abi.decode(payload, (address)); -Key Changes to `tokensConfig`: + // Transfer the received tokens to the intended recipient + IERC20(receivedTokens[0].tokenAddress).transfer( + recipient, + receivedTokens[0].amount + ); + } +} + ``` - - **Capitalized chain names** - all chain names, like `ethereum`, must now be capitalized, such as `Ethereum`, to maintain consistency with the rest of the Wormhole SDK - - **`wrappedTokens`** - this new key replaces `foreignAssets` and defines the wrapped token addresses on foreign chains, making it easier to manage cross-chain transfers. It consolidates the wrapped token addresses into a cleaner structure. These addresses must be specified to enable token transfers to and from the foreign chain via token bridge routes - - **Simplified decimals** - instead of using a map of decimal values for different chains, you now only need to provide a single decimals value for the token's native chain +## Deploy the Contracts -=== "v0.x" +Now that you've written the `CrossChainSender` and `CrossChainReceiver` contracts, it's time to deploy them to your chosen networks. - In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains. +1. **Set up deployment configuration** - before deploying, you must configure the networks and the deployment environment. This information is stored in a configuration file - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + 1. Create a directory named deploy-config in the root of your project: - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'ethereum', - icon: Icon.ETH, - tokenId: { - chain: 'ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: { Ethereum: 18, default: 8 }, - foreignAssets: { - Solana: { - address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - decimals: 8, - }, - }, - }, - }, - }; - ``` -=== "v1.x" + ```bash + mkdir deploy-config + ``` - In v1.0, `foreignAssets` has been replaced with `wrappedTokens`, simplifying token transfers across chains by directly mapping wrapped token addresses. The `decimals` value is now a simple number representing the token’s decimals on its native chain. + 2. Create a `config.json` file in the `deploy-config` directory: - ```typescript - import WormholeConnect, { - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + ```bash + touch deploy-config/config.json + ``` - const config: WormholeConnectConfig = { - tokensConfig: { - WETH: { - key: 'WETH', - symbol: 'WETH', - nativeChain: 'Ethereum', // Chain name now capitalized - icon: Icon.ETH, - tokenId: { - chain: 'Ethereum', - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - }, - coinGeckoId: 'ethereum', - color: '#62688F', - decimals: 18, // Simplified decimals field - }, - }, - wrappedTokens: { - WETH: { - Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', - /* additional chains */ + 3. Open the `config.json` file and add the following configuration: + + ```json + { + "chains": [ + { + "description": "Avalanche testnet fuji", + "chainId": 6, + "rpc": "https://api.avax-test.network/ext/bc/C/rpc", + "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", + "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", + "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" }, - }, - }; - ``` + { + "description": "Celo Testnet", + "chainId": 14, + "rpc": "https://alfajores-forno.celo-testnet.org", + "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", + "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", + "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" + } + ] +} + ``` -### Update NTT Configuration + This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. + For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. -Key changes: + !!! note + You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. - - **Removed `nttGroups`** - the `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttRoutes` function - - **Direct NTT route configuration** - NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers + 4. Create a `contracts.json` file in the `deploy-config` directory: -This change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains. + ```bash + echo '{}' > deploy-config/contracts.json + ``` -=== "v0.x" + This file can be left blank initially. It will be automatically updated with the deployed contract addresses after a successful deployment - In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains. +2. **Set up your Node.js environment** - you'll need to set up your Node.js environment to run the deployment script - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + 1. Initialize a Node.js project: - const config: WormholeConnectConfig = { - nttGroups: { - Lido_wstETH: { - nttManagers: [ - { - chainName: 'ethereum', - address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chainName: 'bsc', - address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - tokenKey: 'wstETH', - transceivers: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }, - }; + ```bash + npm init -y + ``` + + 2. Create a `.gitignore` file to ensure your private key isn't accidentally exposed or committed to version control: + + ```bash + echo ".env" >> .gitignore ``` -=== "v1.x" + + 3. Install the necessary dependencies: - In v1.0, `nttGroups` has been removed, and the configuration is passed to the NTT route constructor as an argument. The tokens and corresponding transceivers are now clearly defined within the `nttRoutes` configuration. + ```bash + npm install ethers dotenv readline-sync @types/readline-sync + ``` - ```typescript - import WormholeConnect, { - nttRoutes, - WormholeConnectConfig, - } from '@wormhole-foundation/wormhole-connect'; + These dependencies are required for the deployment script to work properly. - const config: WormholeConnectConfig = { - routes: [ - ...nttRoutes({ - tokens: { - Lido_wstETH: [ - { - chain: 'Ethereum', - manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9', - token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', - transceiver: [ - { - address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0', - type: 'wormhole', - }, - ], - }, - { - chain: 'Bsc', - manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278', - token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C', - transceiver: [ - { - address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986', - type: 'wormhole', - }, - ], - }, - ], - }, - }), - /* other routes */ - ], - }; - ``` +3. **Compile your smart contracts** - compile your smart contracts using Foundry. This ensures that your contracts are up-to-date and ready for deployment - In this new structure, NTT routes are passed directly through the `nttRoutes` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset. + - Run the following command to compile your contracts: -### Update UI Configuration + ```bash + forge build + ``` -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. + This will generate the necessary ABI and bytecode files in a directory named `/out`. -Key UI changes: + The expected output should be similar to this: - - **Consolidated UI properties** - many UI-related properties moved under a new top-level ui key for better organization - - **Removed `customTheme` and `mode`** - these properties have been removed in favor of a new top-level prop called `theme`, which simplifies theming and allows dynamic switching between themes +
    +forge build + > [⠒] Compiling... + > [⠰] Compiling 30 files with 0.8.23 + [⠔] Solc 0.8.23 finished in 2.29s +Compiler run successful! + +
    -#### UI Properties +4. **Write the deployment script** - you’ll need a script to automate the deployment of your contracts. Let’s create the deployment script -The following properties that were previously defined at the root level of the configuration are now part of the `ui` key: + 1. Create a new file named `deploy.ts` in the `/script` directory: - - `explorer` → `ui.explorer` - specifies the explorer to use for viewing transactions - - `bridgeDefaults` → `ui.defaultInputs` - sets default input values for the bridge, such as the source and destination chains and token - - `pageHeader` → `ui.pageHeader` - sets the title and header for the page - - `menu` → `ui.menu` - defines the menu items displayed in the interface - - `searchTx` → `ui.searchTx` - configures the transaction search functionality - - `partnerLogo` → `ui.partnerLogo` - displays a partner's logo on the interface - - `walletConnectProjectId` → `ui.walletConnectProjectId` - integrates WalletConnect into the UI - - `showHamburgerMenu` → `ui.showHamburgerMenu` - enables or disables the hamburger menu for navigation + ```bash + touch script/deploy.ts + ``` -Additionally, there are two new properties under `ui`: + 2. Open the file and load imports and configuration: - - **`ui.title`** - sets the title rendered in the top left corner of the UI. The default is "Wormhole Connect" - - **`ui.getHelpUrl`** - URL that Connect will render when an unknown error occurs, allowing users to seek help. This can link to a Discord server or any other support channel + ```typescript + import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -```typescript -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; +dotenv.config(); + ``` -const config: WormholeConnectConfig = { - ui: { - title: 'My Custom Bridge Example', - getHelpUrl: 'https://examplehelp.com/', - menu: [ - { - label: 'Support', - href: 'https://examplehelp.com/support', - target: '_blank', - order: 1, // Order of appearance in the menu - }, - { - label: 'About', - href: 'https://examplehelp.com/about', - target: '_blank', - order: 2, - }, - ], - showHamburgerMenu: false, - }, -}; -``` + Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal. -#### UI Configuration + 3. Define interfaces to use for chain configuration and contract deployment: -In the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 1.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability. + ```typescript + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -=== "v0.x" +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} + ``` - ```typescript - const config: WormholeConnectConfig = { - bridgeDefaults: { - fromNetwork: 'solana', - toNetwork: 'ethereum', - tokenKey: 'USDC', - requiredNetwork: 'solana', - }, - showHamburgerMenu: true, - }; - ``` -=== "v1.x" + These interfaces define the structure of the chain configuration and the contract deployment details. - ```typescript - const config: WormholeConnectConfig = { - ui: { - defaultInputs: { - fromChain: 'Solana', // Chain names now capitalized - toChain: 'Ethereum', - tokenKey: 'USDC', - requiredChain: 'Solana', - }, - showHamburgerMenu: true, - }, - }; - ``` + 4. Load and select the chains for deployment: -#### Remove `customTheme` and `mode` Properties + ```typescript + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} -In version 1.0, the `customTheme` and `mode` properties, which were previously used to set themes, have been removed. They have been replaced by a new top-level prop called `theme`, which allows for more flexibility and dynamic updates to themes. +function selectChain( + chains: ChainConfig[], + role: 'source' | 'target' +): ChainConfig { + console.log(`\nSelect the ${role.toUpperCase()} chain:`); + chains.forEach((chain, index) => { + console.log(`${index + 1}: ${chain.description}`); + }); -Important details: + const chainIndex = + readlineSync.questionInt( + `\nEnter the number for the ${role.toUpperCase()} chain: ` + ) - 1; + return chains[chainIndex]; +} + ``` - - The `theme` prop is not part of the `config` object and is passed separately to Wormhole Connect - - `config` cannot be modified after Connect has mounted, but the `theme` can be updated dynamically to support changes such as switching between light and dark modes or updating color schemes + The `loadConfig` function reads the chain configuration from the `config.json` file, and the `selectChain` function allows the user to choose the source and target chains for deployment interactively. The user is prompted in the terminal to select which chains to use, making the process interactive and user-friendly. -=== "v0.x" + 5. Define the main function for deployment and load the chain configuration: - ```typescript - const config: WormholeConnectConfig = { - customTheme: { - primaryColor: '#4266f5', - secondaryColor: '#ff5733', - }, - mode: 'dark', - }; + ```typescript + const chains = loadConfig(); - ; - ``` -=== "v1.x" + const sourceChain = selectChain(chains, 'source'); + const targetChain = selectChain(chains, 'target'); + ``` - ```typescript - const theme: WormholeConnectTheme = { - mode: 'dark', // Can be dynamically changed - font: 'Arial', - button: { - primary: '#4266f5', - }, - }; + - The `main` function is the entry point for the deployment script + - We then call the `loadConfig` function we previously defined to load the chain configuration from the `config.json` file - ; - ``` + 6. Set up provider and wallet: + + ```typescript + const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); + ``` + + The scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction on the source chain. -### Removed Configuration Properties + 7. Read the compiled contracts: -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. + ```typescript + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); + ``` -Removed config keys: + - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract + - The file is in the `../out/` directory, which contains the ABI (Application Binary Interface) and bytecode generated during contract compilation + - It uses the `fs.readFileSync` function to read the file and `JSON.parse` to convert the file contents (in JSON format) into a JavaScript object - - `cta` - - `cctpWarning` - - `pageSubHeader` - - `moreTokens` - - `moreChains` - - `ethBridgeMaxAmount` - - `wstETHBridgeMaxAmount` - - `customTheme` - - `mode` + 8. Extract the contract ABI and bytecode: -If your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v1.0. + ```typescript + const bytecode = senderJson.bytecode; + ``` -## Use the CDN-Hosted Version of Wormhole Connect + - **ABI (Application Binary Interface)** - defines the structure of the contract’s functions, events, and data types, allowing the front end to interact with the contract on the blockchain + - **Bytecode** - this is the compiled machine code that will be deployed to the blockchain to create the contract -For those using the CDN-hosted version of Wormhole Connect, the package's installation and integration have been updated. You must install the Connect package from npm and use the new `wormholeConnectHosted` utility function. + 9. Create the Contract Factory: -### Install and Integrate the Hosted Version + ```typescript + abi, + bytecode, + wallet + ); + ``` -1. Install the Connect package via npm: + - **`ethers.ContractFactory`** - creates a new contract factory using the ABI, bytecode, and a wallet (representing the signer). The contract factory is responsible for deploying instances of the contract to the blockchain + - This is a crucial step for deploying the contract since the factory will create and deploy the `CrossChainSender` contract - ```bash - npm install @wormhole-foundation/wormhole-connect@^1.0 - ``` + 10. Deploy the `CrossChainSender` and `CrossChainReceiver` contracts: -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: + === "`CrossChainSender`" + ```typescript + const senderContract = await CrossChainSenderFactory.deploy( + sourceChain.wormholeRelayer, + sourceChain.tokenBridge, + sourceChain.wormhole + ); + await senderContract.waitForDeployment(); + ``` - ```typescript - import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; + === "`CrossChainReceiver`" + ```typescript + process.env.PRIVATE_KEY!, + targetProvider + ); + const receiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainReceiver.sol/CrossChainReceiver.json' + ), + 'utf8' + ) + ); + const CrossChainReceiverFactory = new ethers.ContractFactory( + receiverJson.abi, + receiverJson.bytecode, + targetWallet + ); - const container = document.getElementById('connect')!; + const receiverContract = await CrossChainReceiverFactory.deploy( + targetChain.wormholeRelayer, + targetChain.tokenBridge, + targetChain.wormhole + ); + await receiverContract.waitForDeployment(); + ``` - wormholeConnectHosted(container); - ``` + Both functions deploy the respective contracts to the selected chains. -### Example: Custom Configuration for Hosted Version + For the `CrossChainReceiver` contract: -The `wormholeConnectHosted` function accepts two parameters: `config` and `theme`. This allows you to customize the routes and apply a theme directly within the hosted version. Here’s an example of how you can pass a custom configuration: + - It defines the wallet related to the target chain + - The logic reads the compiled ABI and bytecode from the JSON file generated during compilation + - It creates a new contract factory using the ABI, bytecode, and wallet + - It deploys the contract to the selected chain passing in the Wormhole Relayer, `TokenBridge`, and Wormhole addresses -```typescript -import { - wormholeConnectHosted, - MayanRoute, -} from '@wormhole-foundation/wormhole-connect'; + 11. Save the deployed contract addresses: -const container = document.getElementById('connect')!; + === "`senderAddress`" + ```typescript + console.log( + `CrossChainSender on ${sourceChain.description}: ${senderAddress}` + ); + ``` -wormholeConnectHosted(container, { - config: { - routes: [MayanRoute], - eventHandler: (e) => { - console.log('Connect event', e); - }, - }, - theme: { - background: { - default: '#004547', - }, - }, -}); -``` + === "`receiverAddress`" + ```typescript + console.log( + `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` + ); + ``` -In this example, the `config` object defines the routes (in this case, using the Mayan route), while the `theme` object allows customization of the Connect interface (e.g., background color). ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/connect/overview/ ---- BEGIN CONTENT --- ---- -title: Wormhole Connect -description: With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. -categories: Connect, Transfer ---- - -# Connect Overview - -With the Wormhole Connect widget, you can enable users to perform multichain asset transfers directly within your application. Connect simplifies the complexity of bridging, offering a single, intuitive point of interaction for moving assets across diverse blockchains. This empowers you to access liquidity and opportunities across any connected network seamlessly. - -## Key Features - -Wormhole connect's notable features include: - -- **In-app multichain transfers**: Bridge assets without leaving your app. -- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. -- **Customizable UI**: Style the bridge interface to match your brand. -- **Optional destination gas**: Provide gas for initial transactions on the target chain. -- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement. + You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference. -Be sure to check the [Feature Support Matrix](/docs/products/connect/reference/support-matrix/#feature-support-matrix){target=\_blank} to find out which routes and features are supported for each chain. + 12. Register the `CrossChainSender` address on the target chain: -## How It Works + ```typescript + receiverAddress, + receiverJson.abi, + targetWallet + ); -When a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including: + const tx = await CrossChainReceiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) + ); -1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. -2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). -3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. -4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. -5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. -6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. -7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. + await tx.wait(); + ``` -!!! tip - If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\_blank}. + After you deploy the `CrossChainReceiver` contract on the target network, the sender contract address from the source chain needs to be registered. This ensures that only messages from the registered `CrossChainSender` contract are processed. -## Use Cases + This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `CrossChainReceiver` contract. -Here are some key use cases that highlight the power and versatility of Connect: + 13. Save the deployment details: -- **Cross-Chain Swaps and Liquidity Aggregation** + ???- example "Save Deployment Details Example" + ```typescript + __dirname, + '../deploy-config/contracts.json' + ); + let deployedContracts: DeployedContracts = {}; - - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + if (fs.existsSync(deployedContractsPath)) { + deployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); + } -- **Cross-Chain Payment Widgets** + // Update the contracts.json file: + // If a contract already exists on a chain, update its address; otherwise, add a new entry. + if (!deployedContracts[sourceChain.chainId]) { + deployedContracts[sourceChain.chainId] = { + networkName: sourceChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[sourceChain.chainId].CrossChainSender = + senderAddress.toString(); + deployedContracts[sourceChain.chainId].deployedAt = + new Date().toISOString(); - - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + if (!deployedContracts[targetChain.chainId]) { + deployedContracts[targetChain.chainId] = { + networkName: targetChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[targetChain.chainId].CrossChainReceiver = + receiverAddress.toString(); + deployedContracts[targetChain.chainId].deployedAt = + new Date().toISOString(); -- **Web3 Game Asset Transfers** + // Save the updated contracts.json file + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); + ``` + + Add your desired logic to save the deployed contract addresses in a JSON file (or another format). This will be important later when transferring tokens, as you'll need these addresses to interact with the deployed contracts. - - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains - - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + 14. Handle errors and finalize the script: -## Next Steps + ```typescript + if (error.code === 'INSUFFICIENT_FUNDS') { + console.error( + 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' + ); + } else { + console.error('An unexpected error occurred:', error.message); + } + process.exit(1); + } +} -Add Connect to your app with these key setup steps: +main().catch((error) => { + console.error(error); + process.exit(1); +}); + ``` -[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] ---- END CONTENT --- + The try-catch block wraps the deployment logic to catch any errors that may occur. -Doc-Content: https://wormhole.com/docs/products/connect/reference/support-matrix/ ---- BEGIN CONTENT --- ---- -title: Features -description: Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. -categories: Connect, Transfer ---- + - If the error is due to insufficient funds, it logs a clear message about needing more gas fees + - For any other errors, it logs the specific error message to help with debugging -## Feature Support Matrix {: #feature-support-matrix} + The `process.exit(1)` ensures that the script exits with a failure status code if any error occurs. -*Scroll down for details about each column.* + You can find the full code for the `deploy.ts` file below: -| **Network** | **Token Bridge** | **Token Bridge Relayer** | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** | -|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:| -| Solana | ✅ | ✅ | ✅ | ❌ | ✅ | -| Ethereum | ✅ | ✅ | ✅ | ✅ | ✅ | -| BSC | ✅ | ✅ | ❌ | ✅ | ✅ | -| Polygon | ✅ | ✅ | ✅ | ✅ | ✅ | -| Avalanche | ✅ | ✅ | ✅ | ✅ | ✅ | -| Fantom | ✅ | ✅ | ❌ | ❌ | ✅ | -| Kaia | ✅ | ❌ | ❌ | ❌ | ❌ | -| Celo | ✅ | ✅ | ❌ | ❌ | ✅ | -| Moonbeam | ✅ | ✅ | ❌ | ❌ | ✅ | -| Injective | ✅ | ❌ | ❌ | ❌ | ❌ | -| Sui | ✅ | ✅ | ✅ | ❌ | ✅ | -| Aptos | ✅ | ❌ | ✅ | ❌ | ❌ | -| Arbitrum | ✅ | ✅ | ✅ | ✅ | ✅ | -| Optimism | ✅ | ✅ | ✅ | ✅ | ✅ | -| Base | ✅ | ✅ | ✅ | ✅ | ✅ | -| Sei | ✅ | ❌ | ❌ | ❌ | ❌ | -| Scroll | ✅ | ❌ | ❌ | ❌ | ❌ | -| Blast | ✅ | ❌ | ❌ | ❌ | ❌ | -| X Layer | ✅ | ❌ | ❌ | ❌ | ❌ | + ??? code "deploy.ts" -## Feature Explanation {: #feature-explanation} + ```solidity + import { BytesLike, ethers } from 'ethers'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -### Token Bridge {: #token-bridge} +dotenv.config(); -Wormhole is best known for its Token Bridge transfer method. It locks assets on the source chain and mints Wormhole-wrapped "IOU" tokens on the destination chain. To transfer the assets back, the Wormhole-wrapped tokens are burned, unlocking the tokens on their original chain. +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -This route appears if both of the following conditions are satisfied: +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} - - Both the origin and destination chains support Token Bridge - - No non-Token Bridge routes are available for the selected token +function loadConfig(): ChainConfig[] { + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} -### Token Bridge Relayer {: #token-bridge-relayer} +function selectChain( + chains: ChainConfig[], + role: 'source' | 'target' +): ChainConfig { + console.log(`\nSelect the ${role.toUpperCase()} chain:`); + chains.forEach((chain, index) => { + console.log(`${index + 1}: ${chain.description}`); + }); -On the [routes](/docs/products/connect/concepts/routes/){target=\_blank} page, this is referred to as the automatic route in the Token Bridge section. + const chainIndex = + readlineSync.questionInt( + `\nEnter the number for the ${role.toUpperCase()} chain: ` + ) - 1; + return chains[chainIndex]; +} -Trustless relayers can execute the second transaction on behalf of the user, so the user only needs to perform one transaction on the origin chain to have the tokens delivered to the destination automatically—for a small fee. +async function main() { + const chains = loadConfig(); -This route appears if all of the following conditions are satisfied: + const sourceChain = selectChain(chains, 'source'); + const targetChain = selectChain(chains, 'target'); -- Both the origin and destination chains support Token Bridge -- Both the origin and destination chains support Token Bridge relayer -- No non-Token Bridge routes are available for the selected token -- The relayer supports the selected token on the origin chain + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); -### Circle CCTP {: #circle-cctp} + const senderJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); -[Circle](https://www.circle.com/en/){target=\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank} chains. + const abi = senderJson.abi; + const bytecode = senderJson.bytecode; -This route appears if all of the following conditions are satisfied: + const CrossChainSenderFactory = new ethers.ContractFactory( + abi, + bytecode, + wallet + ); -- Both the origin and destination chains support Circle CCTP -- The selected token is native Circle-issued USDC + try { + const senderContract = await CrossChainSenderFactory.deploy( + sourceChain.wormholeRelayer, + sourceChain.tokenBridge, + sourceChain.wormhole + ); + await senderContract.waitForDeployment(); -### ETH Bridge {: #eth-bridge} + // Safely access the deployed contract's address + const senderAddress = (senderContract as ethers.Contract).target; + console.log( + `CrossChainSender on ${sourceChain.description}: ${senderAddress}` + ); -[Powered by Uniswap liquidity pools](https://github.com/wormhole-foundation/example-uniswap-liquidity-layer){target=\_blank}, this route can transfer native ETH or wstETH between certain EVMs without going through the native bridges. - -This route appears if all of the following conditions are satisfied: - -- Both the origin and destination chains support the ETH Bridge -- The selected token is native ETH, wstETH, or canonical wETH - -### Gas Drop Off {: #gas-drop-off} - -A relayer can drop off some gas tokens on the destination chain by swapping some of the assets transferred to the native gas token. This is useful if the user wishes to transfer assets to a chain where they don't already have gas. This way, they don't need to onboard into the ecosystem from a centralized exchange. - -This route appears if all of the following conditions are satisfied: + const targetWallet = new ethers.Wallet( + process.env.PRIVATE_KEY!, + targetProvider + ); + const receiverJson = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainReceiver.sol/CrossChainReceiver.json' + ), + 'utf8' + ) + ); + const CrossChainReceiverFactory = new ethers.ContractFactory( + receiverJson.abi, + receiverJson.bytecode, + targetWallet + ); -- Both the origin and destination chains support gas drop off -- An automatic route is selected -- The relayer accepts the selected token to swap into the gas token ---- END CONTENT --- + const receiverContract = await CrossChainReceiverFactory.deploy( + targetChain.wormholeRelayer, + targetChain.tokenBridge, + targetChain.wormhole + ); + await receiverContract.waitForDeployment(); -Doc-Content: https://wormhole.com/docs/products/connect/tutorials/react-dapp/ ---- BEGIN CONTENT --- ---- -title: Integrate Connect into a React DApp Tutorial -description: Learn how to use Wormhole Connect to transfers tokens cross-chain seamlessly between Sui and Avalanche Fuji with this step-by-step guide. -categories: Connect, Transfer ---- + // Safely access the deployed contract's address + const receiverAddress = (receiverContract as ethers.Contract).target; + console.log( + `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` + ); -# Integrate Connect into a React DApp + // Register the sender contract in the receiver contract + console.log( + `Registering CrossChainSender (${senderAddress}) as a valid sender in CrossChainReceiver (${receiverAddress})...` + ); -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank} + const CrossChainReceiverContract = new ethers.Contract( + receiverAddress, + receiverJson.abi, + targetWallet + ); -## Introduction + const tx = await CrossChainReceiverContract.setRegisteredSender( + sourceChain.chainId, + ethers.zeroPadValue(senderAddress as BytesLike, 32) + ); -In this tutorial, we’ll explore how to integrate [Wormhole Connect](https://github.com/wormhole-foundation/wormhole-connect){target=\_blank} to enable cross-chain token transfers and interactions. Wormhole Connect offers a simplified interface for developers to facilitate seamless token transfers between blockchains. Using Wormhole Connect, you can easily bridge assets across multiple ecosystems without diving into the complex mechanics of cross-chain communication. + await tx.wait(); + console.log( + `CrossChainSender registered as a valid sender on ${targetChain.description}` + ); -While this tutorial will guide you through the process using a specific blockchain as an example, the principles and steps outlined here can be applied to any blockchain supported by Wormhole. In this example, we’ll work with Sui as our source blockchain and Avalanche Fuji as the destination blockchain. + // Load existing deployed contract addresses from contracts.json + const deployedContractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + let deployedContracts: DeployedContracts = {}; -## Prerequisites + if (fs.existsSync(deployedContractsPath)) { + deployedContracts = JSON.parse( + fs.readFileSync(deployedContractsPath, 'utf8') + ); + } -To get started with Wormhole Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers. -Before starting this tutorial, ensure you have the following: + // Update the contracts.json file: + // If a contract already exists on a chain, update its address; otherwise, add a new entry. + if (!deployedContracts[sourceChain.chainId]) { + deployedContracts[sourceChain.chainId] = { + networkName: sourceChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[sourceChain.chainId].CrossChainSender = + senderAddress.toString(); + deployedContracts[sourceChain.chainId].deployedAt = + new Date().toISOString(); -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- A [Sui wallet](https://suiwallet.com/){target=\_blank} set up and ready for use -- A [compatible wallet](https://support.avax.network/en/articles/5520938-what-are-the-official-avalanche-wallets){target=\_blank} for Avalanche Fuji, such as [MetaMask](https://metamask.io/){target=\_blank} -- Testnet tokens for [Sui](https://docs.sui.io/guides/developer/getting-started/get-coins){target=\_blank} and [Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} to cover gas fees + if (!deployedContracts[targetChain.chainId]) { + deployedContracts[targetChain.chainId] = { + networkName: targetChain.description, + deployedAt: new Date().toISOString(), + }; + } + deployedContracts[targetChain.chainId].CrossChainReceiver = + receiverAddress.toString(); + deployedContracts[targetChain.chainId].deployedAt = + new Date().toISOString(); -## Set Up Connect for Sui Transfers + // Save the updated contracts.json file + fs.writeFileSync( + deployedContractsPath, + JSON.stringify(deployedContracts, null, 2) + ); + } catch (error: any) { + if (error.code === 'INSUFFICIENT_FUNDS') { + console.error( + 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' + ); + } else { + console.error('An unexpected error occurred:', error.message); + } + process.exit(1); + } +} -### Create a React Project +main().catch((error) => { + console.error(error); + process.exit(1); +}); + ``` -Start by setting up your React app: +5. **Add your private key** - you'll need to provide your private key. It allows your deployment script to sign the transactions that deploy the smart contracts to the blockchain. Without it, the script won't be able to interact with the blockchain on your behalf -1. Open your terminal and run the following command to create a new React app: + Create a `.env` file in the root of the project and add your private key: ```bash - npx create-react-app connect-tutorial + touch .env ``` -2. Navigate into the project directory: + Inside `.env`, add your private key in the following format: - ```bash - cd connect-tutorial + ```env + PRIVATE_KEY=INSERT_PRIVATE_KEY ``` + +6. **Run the deployment script** -### Install Wormhole Connect + 1. Open a terminal and run the following command: -Next, install the Wormhole Connect package as a dependency by running the following command inside your project directory: + ```bash + npx ts-node script/deploy.ts + ``` -```bash -npm install @wormhole-foundation/wormhole-connect -``` + This will execute the deployment script, deploying both contracts to the selected chains. -### Integrate Connect into the Application + 2. Check the deployment output: -Now, we need to modify the default `App.js` file to integrate Wormhole Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\_blank}, make sure to check which version of connect you are using. Open `src/App.js` and replace the content with the following code: + - You will see the deployed contract addresses printed in the terminal if successful. The `contracts.json` file will be updated with these addresses + - If you encounter an error, the script will provide feedback, such as insufficient funds for gas -=== "JavaScript" +If you followed the logic provided in the full code above, your terminal output should look something like this: - ```js - import logo from './logo.svg'; - import './App.css'; - import WormholeConnect from '@wormhole-foundation/wormhole-connect'; +
    +npx ts-node deploy.ts + > cross-chain-token-transfer@1.0.0 deploy + > npx ts-node script/deploy.ts + Select the SOURCE chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the SOURCE chain: 1 + + Select the TARGET chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the TARGET chain: 2 + CrossChainSender Avalanche testnet fuji: 0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3 + CrossChainReceiver Celo Testnet: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 + + Registering CrossChainSender (0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3) as a valid sender in CrossChainReceiver (0xD720BFF42a0960cfF1118454A907a44dB358f2b1)... + + CrossChainSender registered as a valid sender on Celo Testnet + +
    - const config = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], - }; - function App() { - return ; - } +## Transfer Tokens Across Chains - export default App; - ``` +### Quick Recap -=== "TypeScript" +Up to this point, you've set up a new Solidity project using Foundry, developed two key contracts (`CrossChainSender` and `CrossChainReceiver`), and created a deployment script to deploy these contracts to different blockchain networks. The deployment script also saves the new contract addresses for easy reference. With everything in place, it's time to transfer tokens using the deployed contracts. - ```ts - import './App.css'; - import WormholeConnect, { - WormholeConnectConfig, - WormholeConnectTheme, - } from '@wormhole-foundation/wormhole-connect'; +In this step, you'll write a script to transfer tokens across chains using the `CrossChainSender` and `CrossChainReceiver` contracts you deployed earlier. This script will interact with the contracts and facilitate the cross-chain token transfer. - function App() { - const config: WormholeConnectConfig = { - network: 'Testnet', - chains: ['Sui', 'Avalanche'], +### Transfer Script - ui: { - title: 'SUI Connect TS Demo', - }, - }; +1. **Set up the transfer script** - const theme: WormholeConnectTheme = { - mode: 'dark', - primary: '#78c4b6', - }; + 1. Create a new file named `transfer.ts` in the `/script` directory: - return ; - } + ```bash + touch script/transfer.ts + ``` - export default App; - ``` + 2. Open the file. Start with the necessary imports, interfaces and configurations: -- Set `network` to `testnet` - this ensures that Wormhole Connect uses the testnet environment -- Set `chains` to `['Sui', 'Avalanche']` - configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche + ```typescript + import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -### Customize Wormhole Connect +dotenv.config(); -To further customize Wormhole Connect for your application, such as adjusting the UI, adding custom tokens, or configuring specific chain settings, you can refer to the [Wormhole Connect Configuration guide](/docs/products/connect/configuration/data/){target=\_blank}. +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} -### Run the Application +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} + ``` -Make sure you’re in the root directory of your React app, and run the following command to start the application: + These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input. -```bash -npm start -``` + 3. Load configuration and contracts: -Now your React app should be up and running, and Wormhole Connect should be visible on `http://localhost:3000/`. You should see the Wormhole Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers. -## Transfer Tokens from Sui to Fuji + ```typescript + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} -Before transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. +function loadDeployedContracts(): DeployedContracts { + const contractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + if ( + !fs.existsSync(contractsPath) || + fs.readFileSync(contractsPath, 'utf8').trim() === '' + ) { + console.error( + 'No contracts found. Please deploy contracts first before transferring tokens.' + ); + process.exit(1); + } + return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); +} + ``` -To transfer tokens from Sui to Fuji in the Wormhole Connect interface: + These functions load the network and contract details that were saved during deployment. -1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer -2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network -3. Enter the amount of SUI tokens you wish to transfer + 4. Allow users to select source and target chains: - ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp) + Refer to the deployed contracts and create logic as desired. In our example, we made this process interactive, allowing users to select the source and target chains from all the historically deployed contracts. This interactive approach helps ensure the correct chains are selected for the token transfer. -4. Choose to view other routes - - ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp) + ```typescript + chainId: number; + networkName: string; +} { + const sourceOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainSender + ); -5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji) + if (sourceOptions.length === 0) { + console.error('No source chains available with CrossChainSender deployed.'); + process.exit(1); + } - !!! note - It is recommended to use the manual bridge option for this tutorial. The automatic bridge feature is currently undergoing improvements, while the manual bridge ensures that transfers complete successfully. + console.log('\nSelect the source chain:'); + sourceOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp) + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; + return { + chainId: Number(sourceOptions[selectedIndex][0]), + networkName: sourceOptions[selectedIndex][1].networkName, + }; +} -6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain +function selectTargetChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const targetOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainReceiver + ); - ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp) + if (targetOptions.length === 0) { + console.error( + 'No target chains available with CrossChainReceiver deployed.' + ); + process.exit(1); + } -7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet + console.log('\nSelect the target chain:'); + targetOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp) + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; + return { + chainId: Number(targetOptions[selectedIndex][0]), + networkName: targetOptions[selectedIndex][1].networkName, + }; +} + ``` -Once the transaction has been submitted, Wormhole Connect will display the progress of the transfer. Monitor the status until you’re prompted to complete the transaction on the destination chain. You can also track your transactions on [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +2. **Implement the token transfer logic** -## Claim Tokens on Fuji + 1. Start the `main` function: + + ```typescript + const chains = loadConfig(); + const deployedContracts = loadDeployedContracts(); -After the Sui transaction is complete, confirm the final transaction on Fuji by claiming the wrapped tokens. You will be asked to confirm the transaction with your Fuji wallet. + // Select the source chain (only show chains with CrossChainSender deployed) + const { chainId: sourceChainId, networkName: sourceNetworkName } = + selectSourceChain(deployedContracts); + const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; -![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp) + // Select the target chain (only show chains with CrossChainReceiver deployed) + const { chainId: targetChainId, networkName: targetNetworkName } = + selectTargetChain(deployedContracts); + const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; -Once confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received. + // Set up providers and wallets + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); -![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp) + // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); -## Resources + const abi = CrossChainSenderArtifact.abi; -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the entire codebase in the [Sui-Connect GitHub repository](https://github.com/wormhole-foundation/demo-basic-connect){target=\_blank}. The repository includes an integration of Wormhole Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks. + // Create the contract instance using the full ABI + const CrossChainSender = new ethers.Contract( + deployedContracts[sourceChainId].CrossChainSender!, + abi, + wallet + ); + ``` + + The `main` function is where the token transfer logic will reside. It loads the chain and contract details, sets up the wallet and provider, and loads the `CrossChainSender` contract. -## Conclusion + 2. Ask the user for token transfer details: -In this tutorial, you’ve gained hands-on experience with integrating Wormhole Connect to enable cross-chain token transfers. You’ve learned to configure a React app for seamless interactions between Sui and Avalanche Fuji, providing users with the ability to bridge assets across chains with ease. + You'll now ask the user for the token contract address, the recipient address on the target chain, and the amount of tokens to transfer. -By following these steps, you've learned how to: + ```typescript + 'Enter the token contract address: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on the target chain: ' + ); -- Set up a React project tailored for cross-chain transfers -- Install and configure Wormhole Connect to support multiple blockchains -- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers -- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks + // Get the token contract + const tokenContractDecimals = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + ], + wallet + ); -With these tools and knowledge, you’re now equipped to build powerful cross-chain applications using Wormhole Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently. ---- END CONTENT --- + // Fetch the token decimals + const decimals = await tokenContractDecimals.decimals(); -Doc-Content: https://wormhole.com/docs/products/messaging/get-started/ ---- BEGIN CONTENT --- ---- -title: Get Started with Messaging -description: Follow this guide to use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers. -categories: Basics, Typescript-SDK ---- + // Get the amount from the user, then parse it according to the token's decimals + const amount = ethers.parseUnits( + readlineSync.question('Enter the amount of tokens to transfer: '), + decimals + ); + ``` -# Get Started with Messaging + This section of the script prompts the user for the token contract address and the recipient's address, fetches the token's decimal value, and parses the amount accordingly. -Wormhole's core functionality allows you to send any data packet from one supported chain to another. This guide demonstrates how to publish your first simple, arbitrary data message from an EVM environment source chain using the Wormhole TypeScript SDK's core messaging capabilities. + 3. Initiate the transfer: -## Prerequisites + Finally, initiate the cross-chain transfer and log the details. -Before you begin, ensure you have the following: + ```typescript + // Approve the CrossChainSender contract to transfer tokens on behalf of the user + const tokenContract = new ethers.Contract( + tokenAddress, + ['function approve(address spender, uint256 amount) public returns (bool)'], + wallet + ); -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed -- [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed -- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\_blank} installed (this example uses version 6) -- A small amount of testnet tokens for gas fees. This example uses [Sepolia ETH](https://sepolia-faucet.pk910.de/){target=\_blank} but can be adapted for any supported network -- A private key for signing blockchain transactions + const approveTx = await tokenContract.approve( + deployedContracts[sourceChainId].CrossChainSender!, + amount + ); + await approveTx.wait(); + console.log(`Approved tokens for cross-chain transfer.`); -## Configure Your Messaging Environment + // Initiate the cross-chain transfer + const transferTx = await CrossChainSender.sendCrossChainDeposit( + targetChainId, + deployedContracts[targetChainId].CrossChainReceiver!, + recipientAddress, + amount, + tokenAddress, + { value: cost } // Attach the necessary fee for cross-chain transfer + ); + await transferTx.wait(); + console.log( + `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` + ); +} + ``` -1. Create a directory and initialize a Node.js project: + This part of the script first approves the token transfer, then initiates the cross-chain transfer using the `CrossChainSender` contract, and finally logs the transaction hash for the user to track. - ```bash - mkdir core-message - cd core-message - npm init -y - ``` + 4. Finalize the script: -2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js: + ```typescript + console.error(error); + process.exit(1); +}); + ``` - ```bash - npm install --save-dev tsx typescript @types/node ethers - ``` + This section finalizes the script by calling the `main` function and handling any errors that may occur during the token transfer process. -3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command: +You can find the full code for the `transfer.ts` file below: - ```bash - npx tsc --init - ``` +??? code "transfer.ts" - Make sure your `tsconfig.json` includes the following settings: - - ```json - { - "compilerOptions": { - // es2020 or newer - "target": "es2020", - // Use esnext if you configured your package.json with type: "module" - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } - } - ``` - -4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}: - - ```bash - npm install @wormhole-foundation/sdk - ``` - -5. Create a new file named `main.ts`: - - ```bash - touch main.ts - ``` - -## Construct and Publish Your Message - -1. Open `main.ts` and update the code there as follows: - - ```ts title="main.ts" - import { - wormhole, - signSendWait, - toNative, - encoding, - type Chain, - type Network, - type NativeAddress, - type WormholeMessageId, - type UnsignedTransaction, - type TransactionId, - type WormholeCore, - type Signer as WormholeSdkSigner, - type ChainContext, -} from '@wormhole-foundation/sdk'; -// Platform-specific modules -import EvmPlatformLoader from '@wormhole-foundation/sdk/evm'; -import { getEvmSigner } from '@wormhole-foundation/sdk-evm'; -import { - ethers, - Wallet, - JsonRpcProvider, - Signer as EthersSigner, -} from 'ethers'; - -/** - * The required value (SEPOLIA_PRIVATE_KEY) must - * be loaded securely beforehand, for example via a keystore, secrets - * manager, or environment variables (not recommended). - */ + ```solidity + import { ethers } from 'ethers'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as dotenv from 'dotenv'; +import readlineSync from 'readline-sync'; -const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!; -// Provide a private endpoint RPC URL for Sepolia, defaults to a public node -// if not set -const RPC_URL = - process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com'; +dotenv.config(); -async function main() { - // Initialize Wormhole SDK - const network = 'Testnet'; - const wh = await wormhole(network, [EvmPlatformLoader]); - console.log('Wormhole SDK Initialized.'); +interface ChainConfig { + description: string; + chainId: number; + rpc: string; + tokenBridge: string; + wormholeRelayer: string; + wormhole: string; +} - // Get the EVM signer and provider - let ethersJsSigner: EthersSigner; - let ethersJsProvider: JsonRpcProvider; +interface DeployedContracts { + [chainId: number]: { + networkName: string; + CrossChainSender?: string; + CrossChainReceiver?: string; + deployedAt: string; + }; +} - try { - if (!SEPOLIA_PRIVATE_KEY) { - console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.'); - process.exit(1); - } +function loadConfig(): ChainConfig[] { + const configPath = path.resolve(__dirname, '../deploy-config/config.json'); + return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; +} - ethersJsProvider = new JsonRpcProvider(RPC_URL); - const wallet = new Wallet(SEPOLIA_PRIVATE_KEY); - ethersJsSigner = wallet.connect(ethersJsProvider); - console.log( - `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`, +function loadDeployedContracts(): DeployedContracts { + const contractsPath = path.resolve( + __dirname, + '../deploy-config/contracts.json' + ); + if ( + !fs.existsSync(contractsPath) || + fs.readFileSync(contractsPath, 'utf8').trim() === '' + ) { + console.error( + 'No contracts found. Please deploy contracts first before transferring tokens.' ); - } catch (error) { - console.error('Failed to get Ethers.js signer and provider:', error); process.exit(1); } + return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); +} - // Define the source chain context - const sourceChainName: Chain = 'Sepolia'; - const sourceChainContext = wh.getChain(sourceChainName) as ChainContext< - 'Testnet', - 'Sepolia', - 'Evm' - >; - console.log(`Source chain context obtained for: ${sourceChainContext.chain}`); +function selectSourceChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const sourceOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainSender + ); - // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js - // signer using the Wormhole SDK's signing and transaction handling - // capabilities - let sdkSigner: WormholeSdkSigner; - try { - sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner); - console.log( - `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`, - ); - } catch (error) { - console.error('Failed to get Wormhole SDK Signer:', error); + if (sourceOptions.length === 0) { + console.error('No source chains available with CrossChainSender deployed.'); process.exit(1); } - // Construct your message payload - const messageText = `HelloWormholeSDK-${Date.now()}`; - const payload: Uint8Array = encoding.bytes.encode(messageText); - console.log(`Message to send: "${messageText}"`); + console.log('\nSelect the source chain:'); + sourceOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - // Define message parameters - const messageNonce = Math.floor(Math.random() * 1_000_000_000); - const consistencyLevel = 1; + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; + return { + chainId: Number(sourceOptions[selectedIndex][0]), + networkName: sourceOptions[selectedIndex][1].networkName, + }; +} - try { - // Get the core protocol client - const coreProtocolClient: WormholeCore = - await sourceChainContext.getWormholeCore(); +function selectTargetChain(deployedContracts: DeployedContracts): { + chainId: number; + networkName: string; +} { + const targetOptions = Object.entries(deployedContracts).filter( + ([, contracts]) => contracts.CrossChainReceiver + ); - // Generate the unsigned transactions - const whSignerAddress: NativeAddress = toNative( - sdkSigner.chain(), - sdkSigner.address(), - ); - console.log( - `Preparing to publish message from ${whSignerAddress.toString()} on ${ - sourceChainContext.chain - }...`, + if (targetOptions.length === 0) { + console.error( + 'No target chains available with CrossChainReceiver deployed.' ); + process.exit(1); + } - const unsignedTxs: AsyncGenerator> = - coreProtocolClient.publishMessage( - whSignerAddress, - payload, - messageNonce, - consistencyLevel, - ); + console.log('\nSelect the target chain:'); + targetOptions.forEach(([chainId, contracts], index) => { + console.log(`${index + 1}: ${contracts.networkName}`); + }); - // Sign and send the transactions - console.log( - 'Signing and sending the message publication transaction(s)...', - ); - const txIds: TransactionId[] = await signSendWait( - sourceChainContext, - unsignedTxs, - sdkSigner, - ); + const selectedIndex = + readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; + return { + chainId: Number(targetOptions[selectedIndex][0]), + networkName: targetOptions[selectedIndex][1].networkName, + }; +} - if (!txIds || txIds.length === 0) { - throw new Error('No transaction IDs were returned from signSendWait.'); - } - const primaryTxIdObject = txIds[txIds.length - 1]; - const primaryTxid = primaryTxIdObject.txid; +async function main() { + const chains = loadConfig(); + const deployedContracts = loadDeployedContracts(); - console.log(`Primary transaction ID for parsing: ${primaryTxid}`); - console.log( - `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`, - ); + // Select the source chain (only show chains with CrossChainSender deployed) + const { chainId: sourceChainId, networkName: sourceNetworkName } = + selectSourceChain(deployedContracts); + const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; - console.log( - '\nWaiting a few seconds for transaction to propagate before parsing...', - ); - await new Promise((resolve) => setTimeout(resolve, 8000)); + // Select the target chain (only show chains with CrossChainReceiver deployed) + const { chainId: targetChainId, networkName: targetNetworkName } = + selectTargetChain(deployedContracts); + const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; - // Retrieve VAA identifiers - console.log( - `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`, - ); - const messageIds: WormholeMessageId[] = - await sourceChainContext.parseTransaction(primaryTxid); + // Set up providers and wallets + const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); - if (messageIds && messageIds.length > 0) { - const wormholeMessageId = messageIds[0]; - console.log('--- VAA Identifiers (WormholeMessageId) ---'); - console.log(' Emitter Chain:', wormholeMessageId.chain); - console.log(' Emitter Address:', wormholeMessageId.emitter.toString()); - console.log(' Sequence:', wormholeMessageId.sequence.toString()); - console.log('-----------------------------------------'); - } else { - console.error( - `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`, - ); - } - } catch (error) { - console.error( - 'Error during message publishing or VAA identifier retrieval:', - error, - ); - if (error instanceof Error && error.stack) { - console.error('Stack Trace:', error.stack); - } - } + // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) + const CrossChainSenderArtifact = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../out/CrossChainSender.sol/CrossChainSender.json' + ), + 'utf8' + ) + ); + + const abi = CrossChainSenderArtifact.abi; + + // Create the contract instance using the full ABI + const CrossChainSender = new ethers.Contract( + deployedContracts[sourceChainId].CrossChainSender!, + abi, + wallet + ); + + // Display the selected chains + console.log( + `\nInitiating transfer from ${sourceNetworkName} to ${targetNetworkName}.` + ); + + // Ask the user for token transfer details + const tokenAddress = readlineSync.question( + 'Enter the token contract address: ' + ); + const recipientAddress = readlineSync.question( + 'Enter the recipient address on the target chain: ' + ); + + // Get the token contract + const tokenContractDecimals = new ethers.Contract( + tokenAddress, + [ + 'function decimals() view returns (uint8)', + 'function approve(address spender, uint256 amount) public returns (bool)', + ], + wallet + ); + + // Fetch the token decimals + const decimals = await tokenContractDecimals.decimals(); + + // Get the amount from the user, then parse it according to the token's decimals + const amount = ethers.parseUnits( + readlineSync.question('Enter the amount of tokens to transfer: '), + decimals + ); + + // Calculate the cross-chain transfer cost + const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId); + + // Approve the CrossChainSender contract to transfer tokens on behalf of the user + const tokenContract = new ethers.Contract( + tokenAddress, + ['function approve(address spender, uint256 amount) public returns (bool)'], + wallet + ); + + const approveTx = await tokenContract.approve( + deployedContracts[sourceChainId].CrossChainSender!, + amount + ); + await approveTx.wait(); + console.log(`Approved tokens for cross-chain transfer.`); + + // Initiate the cross-chain transfer + const transferTx = await CrossChainSender.sendCrossChainDeposit( + targetChainId, + deployedContracts[targetChainId].CrossChainReceiver!, + recipientAddress, + amount, + tokenAddress, + { value: cost } // Attach the necessary fee for cross-chain transfer + ); + await transferTx.wait(); + console.log( + `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` + ); } -main().catch((e) => { - console.error('Critical error in main function (outer catch):', e); - if (e instanceof Error && e.stack) { - console.error('Stack Trace:', e.stack); - } +main().catch((error) => { + console.error(error); process.exit(1); -}); +}); ``` - This script initializes the SDK, defines values for the source chain, creates an EVM signer, constructs the message, uses the core protocol to generate, sign, and send the transaction, and returns the VAA identifiers upon successful publication of the message. +### Transfer Tokens -2. Run the script using the following command: +Now that your transfer script is ready, it’s time to execute it and perform a cross-chain token transfer. + +1. **Run the transfer script** + + Open your terminal and run the transfer script: ```bash - npx tsx main.ts + npx ts-node script/transfer.ts ``` - You will see terminal output similar to the following: + This command will start the script, prompting you to select the source and target chains, input the token address, recipient address, and the amount of tokens to transfer. -
    -npx tsx main.ts -Wormhole SDK Initialized. -Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 -Source chain context obtained for: Sepolia -Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 -Message to send: "HelloWormholeSDK-1748362375390" -Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia... -Signing and sending the message publication transaction(s)... -Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 -View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508 -Waiting a few seconds for transaction to propagate before parsing... -Attempting to parse VAA identifiers from transaction: - 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508... ---- VAA Identifiers (WormholeMessageId) --- - Emitter Chain: Sepolia - Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12 - Sequence: 1 ------------------------------------------ +2. **Follow the prompts** - the script will guide you through selecting the source and target chains and entering the necessary details for the token transfer. Once you provide all the required information, the script will initiate the token transfer + +3. **Verify the transaction** - after running the script, you should see a confirmation message with the transaction hash. You can use this transaction hash to check the transfer status on the respective blockchain explorers + +You can verify the transaction on the [Wormhole Explorer](https://wormholescan.io/){target=\_balnk} using the link provided in the terminal output. This explorer also offers the option to add the transferred token to your MetaMask wallet automatically. + +If you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this: + +
    +npx ts-node transfer.ts + > cross-chain-token-transfer@1.0.0 transfer + > npx ts-node script/transfer.ts + + Select the source chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the SOURCE chain: 1 + + Select the target chain: + 1: Avalanche testnet fuji + 2: Celo Testnet + + Enter the number for the TARGET chain: 2 + + Initiating transfer from Avalanche testnet fuji to Celo Testnet + Enter the token contract address: 0x5425890298aed601595a70ab815c96711a31bc65 + Enter the recipient address on the target chain: INSERT_YOUR_WALLET_ADDRESS + Enter the amount of tokens to transfer: 2 + Approved tokens for cross-chain transfer. + Transfer initiated from Avalanche testnet fuji to Celo Testnet. Transaction Hash: 0x4a923975d955c1f226a1c2f61a1a0fa1ab1a9e229dc29ceaeadf8ef40acd071f
    -3. Make a note of the transaction ID and VAA identifier values. You can use the transaction ID to [view the transaction on Wormholescan](https://wormholescan.io/#/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508?network=Testnet){target=\_blank}. The emitter chain, emitter address, and sequence values are used to retrieve and decode signed messages +!!! note + In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. We sent two units of USDC Testnet tokens using the token contract address `0x5425890298aed601595a70ab815c96711a31bc65`. You can replace these details with those relevant to your project or use the same for testing purposes. -Congratulations! You've published your first multichain message using Wormhole's TypeScript SDK and core protocol functionality. Consider the following options to build upon what you've accomplished. +## Resources -## Next Steps +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in the [Cross-Chain Token Transfers GitHub repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank}. The repository includes all the scripts, contracts, and configurations needed to deploy and transfer tokens across chains using the Wormhole protocol. -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. +## Conclusion -- [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. +Congratulations! You've successfully built and deployed a cross-chain token transfer system using Solidity and the Wormhole protocol. You've learned how to: + + - Set up a new Solidity project using Foundry + - Develop smart contracts to send and receive tokens across chains + - Write deployment scripts to manage and deploy contracts on different networks --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/guides/core-contracts/ +Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ --- BEGIN CONTENT --- --- -title: Get Started with Core Contracts -description: This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts -categories: Basics +title: Replace Outdated Signatures in VAAs +description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. --- -# Get Started with Core Contracts +# Replace Outdated Signatures in VAAs + +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} ## Introduction -Wormhole's Core Contracts, deployed on each supported blockchain network, enable the fundamental operations of sending and receiving cross-chain messages. +Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. -While the implementation details of the Core Contracts varies by network, the core functionality remains consistent across chains. Each version of the Core Contract facilitates secure and reliable cross-chain communication, ensuring that developers can effectively publish and verify messages. +However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. -This guide will walk you through the variations and key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your cross-chain contracts. To learn more about Core Contracts' features and how it works, please refer to the [Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank} page in the Learn section. +Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. -## Prerequisites +In this tutorial, you'll build a script from scratch to: -To interact with the Wormhole Core Contract, you'll need the following: +- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} +- Validate its signatures against the latest Guardian set +- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} +- Output a valid VAA ready for submission -- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on the chains you're deploying your contract on -- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're deploying your contract on -- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on +By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. -## How to Interact with Core Contracts +## Prerequisites -Before writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around: +Before you begin, ensure you have the following: -- **Sending messages** - submitting messages to the Wormhole network for cross-chain communication -- **Receiving and verifying messages** - validating messages received from other chains via the Wormhole network + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally -While the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains. +## Project Setup -### Sending Messages +In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +1. **Create the project** - set up the directory and navigate into it -=== "EVM" + ```bash + mkdir wormhole-scan-api-demo + cd wormhole-scan-api-demo + ``` - The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract: +2. **Initialize a Node.js project** - generate a `package.json` file - ```solidity - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel -) external payable returns (uint64 sequence); + ```bash + npm init -y ``` - ??? interface "Parameters" +3. **Set up TypeScript** - create a `tsconfig.json` file - `nonce` ++"uint32"++ - - A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest. + ```bash + touch tsconfig.json + ``` - --- + Then, add the following configuration: - `payload` ++"bytes memory"++ - - The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length. + ```json title="tsconfig.json" + { + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} + ``` - --- +4. **Install dependencies** - add the required packages - `consistencyLevel` ++"uint8"++ - - A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events. + ```bash + npm install @wormhole-foundation/sdk axios web3 tsx @types/node + ``` - ??? interface "Returns" + - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions + - `axios` - makes HTTP requests to the Wormholescan API + - `web3` - interacts with Ethereum transactions and contracts + - `tsx` - executes TypeScript files without compilation + - `@types/node` - provides Node.js type definitions - `sequence` ++"uint64"++ - - A unique number that increments for every message for a given emitter (and implicitly chain). This, combined with the emitter address and emitter chain ID, allows the VAA for this message to be queried from the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank}. - - ??? interface "Example" +5. **Create the project structure** - set up the required directories and files - ```solidity - IWormhole wormhole = IWormhole(wormholeAddr); + ```bash + mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts + mkdir -p src/helpers && touch src/helpers/vaaHelper.ts + mkdir -p src/scripts && touch scripts/replaceSignatures.ts + ``` -// Get the fee for publishing a message -uint256 wormholeFee = wormhole.messageFee(); + - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures + - **`src/helpers/*`** - contains utility functions + - **`src/scripts/*`** - contains scripts for fetching and replacing signatures -// Check fee and send parameters +6. **Set variables** - define key constants in `src/config/constants.ts` -// Create the HelloWorldMessage struct -HelloWorldMessage memory parsedMessage = HelloWorldMessage({ - payloadID: uint8(1), - message: helloWorldMessage -}); + ```bash title="src/config/constants.ts" + export const RPC = 'https://ethereum-rpc.publicnode.com'; -// Encode the HelloWorldMessage struct into bytes -bytes memory encodedMessage = encodeMessage(parsedMessage); +export const ETH_CORE = + '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase(); -// Send the HelloWorld message by calling publishMessage on the -// wormhole core contract and paying the Wormhole protocol fee. -messageSequence = wormhole.publishMessage{value: wormholeFee}( - 0, // batchID - encodedMessage, - wormholeFinality() -); - ``` +export const WORMHOLESCAN_API = 'https://api.wormholescan.io/v1'; - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. +export const LOG_MESSAGE_PUBLISHED_TOPIC = + '0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2'; -=== "Solana" +export const TXS = [ + '0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367', + '0x3c989a6bb40dcd4719453fbe7bbac420f23962c900ae75793124fc9cc614368c', +]; + ``` - The `wormhole_anchor_sdk::wormhole` module and the Wormhole program account can be used to pass a message directly to the Core Contract via the `wormhole::post_message` function: + - **`RPC`** - endpoint for interacting with an Ethereum RPC node + - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs + - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets + - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts + - **`TXS`** - list of example transaction hashes that will be used for testing - ```rs - pub fn post_message<'info>( - ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>, - batch_id: u32, - payload: Vec, - finality: Finality - ) -> Result<()> - ``` +7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs - ??? interface "Parameters" + ```typescript title="src/config/layouts.ts" + export const PARSE_AND_VERIFY_VM_ABI = { + inputs: [{ internalType: 'bytes', name: 'encodedVM', type: 'bytes' }], + name: 'parseAndVerifyVM', + outputs: [ + { + components: [ + { internalType: 'uint8', name: 'version', type: 'uint8' }, + { internalType: 'uint32', name: 'timestamp', type: 'uint32' }, + { internalType: 'uint32', name: 'nonce', type: 'uint32' }, + { internalType: 'uint16', name: 'emitterChainId', type: 'uint16' }, + { internalType: 'bytes32', name: 'emitterAddress', type: 'bytes32' }, + { internalType: 'uint64', name: 'sequence', type: 'uint64' }, + { internalType: 'uint8', name: 'consistencyLevel', type: 'uint8' }, + { internalType: 'bytes', name: 'payload', type: 'bytes' }, + { internalType: 'uint32', name: 'guardianSetIndex', type: 'uint32' }, + { + components: [ + { internalType: 'bytes32', name: 'r', type: 'bytes32' }, + { internalType: 'bytes32', name: 's', type: 'bytes32' }, + { internalType: 'uint8', name: 'v', type: 'uint8' }, + { internalType: 'uint8', name: 'guardianIndex', type: 'uint8' }, + ], + internalType: 'struct Structs.Signature[]', + name: 'signatures', + type: 'tuple[]', + }, + { internalType: 'bytes32', name: 'hash', type: 'bytes32' }, + ], + internalType: 'struct Structs.VM', + name: 'vm', + type: 'tuple', + }, + { internalType: 'bool', name: 'valid', type: 'bool' }, + { internalType: 'string', name: 'reason', type: 'string' }, + ], + stateMutability: 'view', + type: 'function', +}; + ``` - `ctx` ++"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>"++ - - Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI). +## Create VAA Handling Functions - ??? child "Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`" +In this section, we'll create a series of helper functions in the `src/helpers/vaaHelper.ts` file that will retrieve and verify VAAs and fetch and replace outdated Guardian signatures to generate a correctly signed VAA. - ```rs - pub struct CpiContext<'a, 'b, 'c, 'info, T> - where - T: ToAccountMetas + ToAccountInfos<'info>, - { - pub accounts: T, - pub remaining_accounts: Vec>, - pub program: AccountInfo<'info>, - pub signer_seeds: &'a [&'b [&'c [u8]]], - } - ``` +To get started, import the necessary dependencies: - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/anchor-lang/0.29.0/anchor_lang/context/struct.CpiContext.html){target=\_blank}. +```typescript title="src/helpers/vaaHelper.ts" +import { eth } from 'web3'; +import { + deserialize, + serialize, + VAA, + Signature, +} from '@wormhole-foundation/sdk'; +import { + RPC, + ETH_CORE, + LOG_MESSAGE_PUBLISHED_TOPIC, + WORMHOLESCAN_API, +} from '../config/constants'; +import { PARSE_AND_VERIFY_VM_ABI } from '../config/layouts'; +``` - ??? child "Type `PostMessage<'info>`" +### Fetch a VAA ID from a Transaction - ```rs - pub struct PostMessage<'info> { - pub config: AccountInfo<'info>, - pub message: AccountInfo<'info>, - pub emitter: AccountInfo<'info>, - pub sequence: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub fee_collector: AccountInfo<'info>, - pub clock: AccountInfo<'info>, - pub rent: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, - } - ``` +To retrieve a VAA, we first need to get its VAA ID from a transaction hash. This ID allows us to fetch the full VAA later. +The VAA ID is structured as follows: - For more information, please refer to the [`wormhole_anchor_sdk` Rust docs](https://docs.rs/wormhole-anchor-sdk/latest/wormhole_anchor_sdk/wormhole/instructions/struct.PostMessage.html){target=\_blank}. +```bash +chain/emitter/sequence +``` - --- + - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) + - `emitter` - the contract address that emitted the VAA + - `sequence` - a unique identifier for the event - `batch_id` ++"u32"++ - - An identifier for the message batch. +We must assemble the ID correctly since this is the format the Wormholescan API expects when querying VAAs. - --- +Follow the below steps to process the transaction logs and construct the VAA ID: - `payload` ++"Vec"++ - - The data being sent in the message. This is a variable-length byte array that contains the actual content or information being transmitted. To learn about the different types of payloads, check out the [VAAs](/docs/protocol/infrastructure/vaas#payload-types){target=\_blank} page. +1. **Get the transaction receipt** - iterate over the array of transaction hashes and fetch the receipt to access its logs - --- +2. **Find the Wormhole event** - iterate over the transaction logs and check for events emitted by the Wormhole Core contract. Look specifically for `LogMessagePublished` events, which indicate a VAA was created - `finality` ++"Finality"++ - - Specifies the level of finality or confirmation required for the message. - - ??? child "Type `Finality`" +3. **Extract the emitter and sequence number** - if a matching event is found, extract the emitter address from `log.topics[1]` and remove the `0x` prefix. Then, the sequence number from `log.data` is extracted, converting it from hex to an integer - ```rs - pub enum Finality { - Confirmed, - Finalized, - } - ``` - - ??? interface "Returns" +4. **Construct the VAA ID** - format the extracted data in `chain/emitter/sequence` format - ++"Result<()>"++ - - The result of the function’s execution. If the function completes successfully, it returns `Ok(())`, otherwise it returns `Err(E)`, indicating that an error occurred along with the details about the error - - ??? interface "Example" +```typescript title="src/helpers/vaaHelper.ts" +const vaaIds: string[] = []; - ```rust - let fee = ctx.accounts.wormhole_bridge.fee(); -// ... Check fee and send parameters + for (const tx of txHashes) { + try { + const result = ( + await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_getTransactionReceipt', + params: [tx], + }) + ).data.result; -let config = &ctx.accounts.config -let payload: Vec = HelloWorldMessage::Hello { message }.try_to_vec()?; + if (!result) + throw new Error(`Unable to fetch transaction receipt for ${tx}`); -// Invoke `wormhole::post_message`. -wormhole::post_message( - CpiContext::new_with_signer( - ctx.accounts.wormhole_program.to_account_info(), - wormhole::PostMessage { - // ... Set fields - }, - &[ - // ... Set seeds - ], - ), - config.batch_id, - payload, - config.finality.into(), -)?; - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. + for (const log of result.logs) { + if ( + log.address === ETH_CORE && + log.topics?.[0] === LOG_MESSAGE_PUBLISHED_TOPIC + ) { + const emitter = log.topics[1].substring(2); + const seq = BigInt(log.data.substring(0, 66)).toString(); + vaaIds.push(`2/${emitter}/${seq}`); + } + } + } catch (error) { + console.error(`Error processing ${tx}:`, error); + } + } -Once the message is emitted from the Core Contract, the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} will observe the message and sign the digest of an Attestation [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. On EVM chains, the body of the VAA is hashed twice with keccak256 to produce the signed digest message. On Solana, the [Solana secp256k1 program](https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. + return vaaIds; +} +``` -VAAs are [multicast](/docs/protocol/infrastructure/core-contracts/#multicast){target=\_blank} by default. This means there is no default target chain for a given message. The application developer decides on the format of the message and its treatment upon receipt. +???- code "Try it out: VAA ID retrieval" + If you want to try out the function before moving forward, create a test file inside the `test` directory: -### Receiving Messages + 1. **Create the directory and file** - add a script to call `fetchVaaId` and print the result -The way a message is received and handled depends on the environment. + ```bash + mkdir -p test + touch test/fetchVaaId.run.ts + ``` + 2. **Add the function call** -=== "EVM" + ```typescript title="test/fetchVaaId.run.ts" + import { fetchVaaId } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; - On EVM chains, the message passed is the raw VAA encoded as binary. The `IWormhole.sol` interface provides the `parseAndVerifyVM` function, which can be used to parse and verify the received message. +const testFetchVaaId = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); - ```solidity - function parseAndVerifyVM( - bytes calldata encodedVM -) external view returns (VM memory vm, bool valid, string memory reason); - ``` + if (vaaIds.length > 0) { + console.log(`Transaction: ${tx}`); + vaaIds.forEach((vaaId) => console.log(`VAA ID: ${vaaId}`)); + } else { + console.log(`No VAA ID found for transaction: ${tx}`); + } + } +}; - ??? interface "Parameters" +testFetchVaaId(); + ``` - `encodedVM` ++"bytes calldata"++ - - The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing. + 3. **Run the script** - ??? interface "Returns" + ```bash + npx tsx test/fetchVaaId.run.ts + ``` - `vm` ++"VM memory"++ - - The valid parsed VAA, which will include the original `emitterAddress`, `sequenceNumber`, and `consistencyLevel`, among other fields outlined on the [VAAs](/docs/protocol/infrastructure/vaas/) page. + If successful, the output will be: - ??? child "Struct `VM`" +
    +npx tsx test/fetchVaaId.run.ts + +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +VAA ID: 2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/164170 + +
    - ```solidity - struct VM { - uint8 version; - uint32 timestamp; - uint32 nonce; - uint16 emitterChainId; - bytes32 emitterAddress; - uint64 sequence; - uint8 consistencyLevel; - bytes payload; - uint32 guardianSetIndex; - Signature[] signatures; - bytes32 hash; - } - ``` + If no VAA ID is found, the script will log an error message. - For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}. +### Fetch the Full VAA - --- - - `valid` ++"bool"++ - - A boolean indicating whether the VAA is valid or not. - - --- +Now that you have the VAA ID, we can use it to fetch the full VAA payload from the Wormholescan API. This payload contains the VAA bytes, which will later be used for signature validation. - `reason` ++"string"++ - - If the VAA is not valid, a reason will be provided +Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload. - ??? interface "Example" +```typescript title="src/helpers/vaaHelper.ts" +vaaIds: string[] +): Promise<{ id: string; vaaBytes: string }[]> { + const results: { id: string; vaaBytes: string }[] = []; - ```solidity - function receiveMessage(bytes memory encodedMessage) public { - // Call the Wormhole core contract to parse and verify the encodedMessage - ( - IWormhole.VM memory wormholeMessage, - bool valid, - string memory reason - ) = wormhole().parseAndVerifyVM(encodedMessage); + for (const id of vaaIds) { + try { + const response = await axios.get(`${WORMHOLESCAN_API}/signed_vaa/${id}`); + const vaaBytes = response.data.vaaBytes; + results.push({ id, vaaBytes }); + } catch (error) { + console.error(`Error fetching VAA for ${id}:`, error); + } + } + return results; +} +``` - // Perform safety checks here +???- code "Try it out: VAA retrieval" + If you want to try the function before moving forward, create a script inside the `test` directory - // Decode the message payload into the HelloWorldMessage struct - HelloWorldMessage memory parsedMessage = decodeMessage( - wormholeMessage.payload - ); + 1. **Create the script file** - // Your custom application logic here -} + ```bash + touch test/fetchVaa.run.ts ``` - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/evm/src/01_hello_world){target=\_blank} repository on GitHub. - -=== "Solana" - - On Solana, the VAA is first posted and verified by the Core Contract, after which it can be read by the receiving contract and action taken. + 2. **Add the function call** - Retrieve the raw message data: + ```typescript title="test/fetchVaa.run.ts" + import { fetchVaaId, fetchVaa } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; - ```rs - let posted_message = &ctx.accounts.posted; - posted_message.data() - ``` +const testFetchVaa = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); - ??? interface "Example" + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } - ```rust - pub fn receive_message(ctx: Context, vaa_hash: [u8; 32]) -> Result<()> { - let posted_message = &ctx.accounts.posted + for (const vaaId of vaaIds) { + const vaaBytes = await fetchVaa([vaaId]); - if let HelloWorldMessage::Hello { message } = posted_message.data() { - // Check message - // Your custom application logic here - Ok(()) - } else { - Err(HelloWorldError::InvalidMessage.into()) + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Bytes: ${ + vaaBytes.length > 0 ? vaaBytes[0].vaaBytes : 'Not found' + }` + ); } -} - - ``` - - View the complete Hello World example in the [Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding/tree/main/solana/programs/01_hello_world){target=\_blank} repository on GitHub. + } +}; -#### Validating the Emitter +testFetchVaa(); + ``` -When processing cross-chain messages, it's critical to ensure that the message originates from a trusted sender (emitter). This can be done by verifying the emitter address and chain ID in the parsed VAA. + 3. **Run the script** -Typically, contracts should provide a method to register trusted emitters and check incoming messages against this list before processing them. For example, the following check ensures that the emitter is registered and authorized: + ```bash + npx tsx test/fetchVaa.run.ts + ``` -```solidity -require(isRegisteredSender(emitterChainId, emitterAddress), "Invalid emitter"); -``` + If successful, the output will be: -This check can be applied after the VAA is parsed, ensuring only authorized senders can interact with the receiving contract. Trusted emitters can be registered using a method like `setRegisteredSender` during contract deployment or initialization. +
    +npx tsx test/fetchVaa.run.ts + +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +VAA Bytes: AQAAAAMNANQSwD/HRPcKp7Yxypl1ON8dZeMBzgYJrd2KYz6l9Tq9K9fj72fYJgkMeMaB9h... + +
    -```typescript -const tx = await receiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) -); + If no VAA is found, the script will log an error message. -await tx.wait(); -``` +### Validate VAA Signatures -#### Additional Checks +Now, we need to verify its validity. A VAA is only considered valid if it contains signatures from currently active Guardians and is correctly verified by the Wormhole Core contract. -In addition to environment-specific checks that should be performed, a contract should take care to check other [fields in the body](/docs/protocol/infrastructure/vaas/){target=\_blank}, including: +Open `src/helpers/vaaHelper.ts` and add the `checkVaaValidity()` function. This function verifies whether a VAA is valid by submitting it to an Ethereum RPC node and checking for outdated signatures. -- **Sequence** - is this the expected sequence number? How should out-of-order deliveries be handled? -- **Consistency level** - for the chain this message came from, is the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} level enough to guarantee the transaction won't be reverted after taking some action? +Follow these steps to implement the function: -The VAA digest is separate from the VAA body but is also relevant. It can be used for replay protection by checking if the digest has already been seen. Since the payload itself is application-specific, there may be other elements to check to ensure safety. +1. **Prepare the VAA for verification** - construct the VAA payload in a format that can be sent to the Wormhole Core contract -## Source Code References +2. **Send an `eth_call` request** - submit the VAA to an Ethereum RPC node, calling the `parseAndVerifyVM` function on the Wormhole Core contract -For a deeper understanding of the Core Contract implementation for a specific blockchain environment and to review the actual source code, please refer to the following links: +3. **Decode the response** - check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them -- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\_blank} -- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\_blank} -- [EVM Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/ethereum/contracts){target=\_blank} ([`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}) -- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\_blank} -- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\_blank} -- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\_blank} -- [Terra Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/terra/contracts/wormhole){target=\_blank} ---- END CONTENT --- +```typescript title="src/helpers/vaaHelper.ts" +try { + const vaa = Buffer.from(vaaBytes, 'base64'); + vaa[4] = 4; // Set guardian set index to 4 -Doc-Content: https://wormhole.com/docs/products/messaging/guides/wormhole-relayers/ ---- BEGIN CONTENT --- ---- -title: Wormhole-Deployed Relayers -description: Learn about the Wormhole-deployed relayer configuration for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -categories: Relayers, Basics ---- - -# Wormhole Relayer - -## Introduction + const result = ( + await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [ + `0x${vaa.toString('hex')}`, + ]), + }, + 'latest', + ], + }) + ).data.result; -The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to [run a custom relayer](/docs/protocol/infrastructure-guides/run-relayer/) is available for more complex needs. + const decoded = eth.abi.decodeParameters( + PARSE_AND_VERIFY_VM_ABI.outputs, + result + ); + console.log( + `${decoded.valid ? '✅' : '❌'} VAA Valid: ${decoded.valid}${ + decoded.valid ? '' : `, Reason: ${decoded.reason}` + }` + ); -This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool. + return { valid: decoded.valid, reason: decoded.reason }; + } catch (error) { + console.error(`Error checking VAA validity:`, error); + return { valid: false, reason: 'RPC error' }; + } +} +``` -## Get Started with the Wormhole Relayer +???- code "Try it out: VAA Validity" + If you want to try the function before moving forward, create a script inside the `test` directory -Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently **limited to EVM environments**. The complete list of EVM environment blockchains is on the [Supported Networks](/docs/products/reference/supported-networks/) page. + 1. **Create the script file** -To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying. + ```bash + touch test/checkVaaValidity.run.ts + ``` -
    - ![Wormhole Relayer](/docs/images/products/messaging/guides/wormhole-relayers/relayer-1.webp) -
    The components outlined in blue must be implemented.
    -
    + 2. **Add the function call** -### Wormhole Relayer Interfaces + ```typescript title="test/checkVaaValidity.run.ts" + import { + fetchVaaId, + fetchVaa, + checkVaaValidity, +} from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -There are three relevant interfaces to discuss when utilizing the Wormhole relayer module: +const testCheckVaaValidity = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); -- [**`IWormholeRelayer`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol){target=\_blank} - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs -- [**`IWormholeReceiver`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol){target=\_blank} - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract -- [**`IDeliveryProvider`**](https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IDeliveryProvider.sol){target=\_blank} - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } -## Interact with the Wormhole Relayer + for (const vaaId of vaaIds) { + const vaaData = await fetchVaa([vaaId]); -To start interacting with the Wormhole relayer in your contracts, you'll need to import the `IWormholeRelayer` interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice. + if (vaaData.length === 0 || !vaaData[0].vaaBytes) { + console.log(`VAA not found for ID: ${vaaId}`); + continue; + } -To easily integrate with the Wormhole relayer interface, you can use the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. + const result = await checkVaaValidity(vaaData[0].vaaBytes); + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Validity:`, + result + ); + } + } +}; -To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the [Contract Addresses](/docs/products/reference/contract-addresses/#wormhole-relayer) reference page. +testCheckVaaValidity(); + ``` -Your initial set up should resemble the following: + 3. **Run the script** -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.26; + ```bash + npx tsx test/checkVaaValidity.run.ts + ``` -import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol"; + If the VAA is valid, the output will be: -contract Example { - IWormholeRelayer public wormholeRelayer; +
    +npx tsx test/checkVaaValidity.run.ts + +✅ VAA Valid: true + +
    - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - } -} -``` + If invalid, the output will include the reason: -The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the `IWormholeRelayer` interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks. +
    +npx tsx test/checkVaaValidity.run.ts + +❌ VAA Valid: false, Reason: VM signature invalid +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 + +
    -### Send a Message +### Fetch Observations (VAA Signatures) -To send a message to a contract on another EVM chain, you can call the `sendPayloadToEvm` method provided by the `IWormholeRelayer` interface. +Before replacing outdated signatures, we need to fetch the original VAA signatures from Wormholescan. This allows us to compare them with the latest Guardian set and determine which ones need updating. -```solidity -function sendPayloadToEvm( - // Chain ID in Wormhole format - uint16 targetChain, - // Contract Address on target chain we're sending a message to - address targetAddress, - // The payload, encoded as bytes - bytes memory payload, - // How much value to attach to the delivery transaction - uint256 receiverValue, - // The gas limit to set on the delivery transaction - uint256 gasLimit -) external payable returns ( - // Unique, incrementing ID, used to identify a message - uint64 sequence -); -``` +Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to query the Wormholescan API for observations related to a given VAA. Format the response by converting Guardian addresses to lowercase for consistency, and return an empty array if an error occurs. -!!! tip - To reduce transaction confirmation time, you can lower the consistency level using the [`sendToEvm`](https://github.com/wormhole-foundation/wormhole/blob/v{{repositories.wormhole.version}}/sdk/js/src/relayer/relayer/send.ts#L33){target=\_blank} method. +```typescript title="src/helpers/vaaHelper.ts" +try { + console.log(`Fetching observations`); -The `sendPayloadToEvm` method is marked `payable` to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the `quoteEVMDeliveryPrice`, which provides an estimate of the cost of gas on the target chain. + const response = await axios.get( + `https://api.wormholescan.io/api/v1/observations/${vaaId}` + ); -```solidity -function quoteEVMDeliveryPrice( - // Chain ID in Wormhole format - uint16 targetChain, - // How much value to attach to delivery transaction - uint256 receiverValue, - // The gas limit to attach to the delivery transaction - uint256 gasLimit -) external view returns ( - // How much value to attach to the send call - uint256 nativePriceQuote, - uint256 targetChainRefundPerGasUnused -); + return response.data.map((obs: any) => ({ + guardianAddr: obs.guardianAddr.toLowerCase(), + signature: obs.signature, + })); + } catch (error) { + console.error(`Error fetching observations:`, error); + return []; + } +} ``` -This method should be called before sending a message, and the value returned for `nativePriceQuote` should be attached to the call to send the payload to cover the transaction's cost on the target chain. +???- code "Try it out: Fetch Observations" + If you want to try the function before moving forward, create a script inside the `test` directory -In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows: + 1. **Create the script file** -```solidity -// Get a quote for the cost of gas for delivery -(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - valueToSend, - GAS_LIMIT -); + ```bash + touch test/fetchObservations.run.ts + ``` -// Send the message -wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(payload), - valueToSend, - GAS_LIMIT -); -``` + 2. **Add the function call** -### Receive a Message + ```typescript title="test/fetchObservations.run.ts" + import { fetchVaaId, fetchObservations } from '../src/helpers/vaaHelper'; +import { TXS } from '../src/config/constants'; -To receive a message using a Wormhole relayer, the target contract must implement the [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-relayer-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interface, as shown in the [previous section](#interact-with-the-wormhole-relayer). +const testFetchObservations = async () => { + for (const tx of TXS) { + const vaaIds = await fetchVaaId([tx]); -```solidity -function receiveWormholeMessages( - bytes memory payload, // Message passed by source contract - bytes[] memory additionalVaas, // Any additional VAAs that are needed (Note: these are unverified) - bytes32 sourceAddress, // The address of the source contract - uint16 sourceChain, // The Wormhole chain ID - bytes32 deliveryHash // A hash of contents, useful for replay protection -) external payable; -``` + if (vaaIds.length === 0) { + console.log(`No VAA ID found for transaction: ${tx}`); + continue; + } -The logic inside the function body may be whatever business logic is required to take action on the specific payload. + for (const vaaId of vaaIds) { + const observations = await fetchObservations(vaaId); -## Delivery Guarantees + if (observations.length === 0) { + console.log(`No observations found for VAA ID: ${vaaId}`); + continue; + } -The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe. + console.log( + `Transaction: ${tx}\nVAA ID: ${vaaId}\nObservations:`, + observations + ); + } + } +}; -This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss. +testFetchObservations(); + ``` -Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees. + 3. **Run the script** -## Delivery Statuses + ```bash + npx tsx test/fetchObservations.run.ts + ``` -All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are: + If successful, the output will be: -- (0) Delivery Success -- (1) Receiver Failure -- (2) Forward Request Success -- (3) Forward Request Failure +
    +npx tsx test/fetchObservations.run.ts + +Fetching observations +Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +Observations: [ { guardianAddr: '0xda798f6896a3331f64b48c12d1d57fd9cbe70811', signature: + 'ZGFlMDYyOGNjZjFjMmE0ZTk5YzE2OThhZjAzMDM4NzZlYTM1OWMxMzczNDA3YzdlMDMxZTkyNzk0ODkwYjRiYjRiOWFmNzM3NjRiMzIyOTE0ZTQwYzNlMjllMWEzNmM2NTc3ZDc5ZTdhNTM2MzA5YjA4YjExZjE3YzE3MDViNWIwMQ==' + }, { guardianAddr: '0x74a3bf913953d695260d88bc1aa25a4eee363ef0', signature: + 'MzAyOTU4OGU4MWU0ODc0OTAwNDU3N2EzMGZlM2UxMDJjOWYwMjM0NWVhY2VmZWQ0ZGJlNTFkNmI3YzRhZmQ5ZTNiODFjNTg3MDNmYzUzNmJiYWFiZjNlODc1YTY3OTQwMGE4MmE3ZjZhNGYzOGY3YmRmNDNhM2VhNGQyNWNlNGMwMA==' + }, +...] + +
    -A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are: + If no observations are found, the script will log an error message. -- The target contract does not implement the `IWormholeReceiver` interface -- The target contract threw an exception or reverted during the execution of `receiveWormholeMessages` -- The target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages` +### Fetch the Latest Guardian Set -All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves. +Now that we have the original VAA signatures, we must fetch the latest Guardian set from Wormholescan. This will allow us to compare the stored signatures with the current Guardians and determine which signatures need replacing. -`Forward Request Success` and `Forward Failure` represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be `Forward Request Success`. Otherwise, it will be `Forward Request Failure`. +Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set. -## Other Considerations +```typescript title="src/helpers/vaaHelper.ts" +export async function fetchGuardianSet() { + try { + console.log('Fetching current guardian set'); -Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas: + const response = await axios.get(`${WORMHOLESCAN_API}/guardianset/current`); + const guardians = response.data.guardianSet.addresses.map((addr: string) => + addr.toLowerCase() + ); + const guardianSet = response.data.guardianSet.index; -- Receiving a message from a relayer -- Checking for expected emitter -- Calling `parseAndVerify` on any additional VAAs -- Replay protection -- Message ordering (no guarantees on order of messages delivered) -- Forwarding and call chaining -- Refunding overpayment of `gasLimit` -- Refunding overpayment of value sent + return [guardians, guardianSet]; + } catch (error) { + console.error('Error fetching guardian set:', error); + return []; + } +} +``` -## Track the Progress of Messages with the Wormhole CLI +???- code "Try it out: Fetch Guardian Set" + If you want to try the function before moving forward, create a script inside the `test` directory -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: + 1. **Create the script file** -=== "Mainnet" + ```bash + touch test/fetchGuardianSet.run.ts + ``` - ```bash - worm status mainnet ethereum INSERT_TRANSACTION_HASH - ``` + 2. **Add the function call** -=== "Testnet" + ```typescript title="test/fetchGuardianSet.run.ts" + import { fetchGuardianSet } from '../src/helpers/vaaHelper'; - ```bash - worm status testnet ethereum INSERT_TRANSACTION_HASH - ``` +const testFetchGuardianSet = async () => { + const [guardians, guardianSetIndex] = await fetchGuardianSet(); -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. + console.log('Current Guardian Set Index:', guardianSetIndex); + console.log('Guardian Addresses:', guardians); +}; -## Step-by-Step Tutorial +testFetchGuardianSet(); + ``` -For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the [Create Cross-Chain Contracts](/docs/products/messaging/tutorials/cross-chain-contracts/) tutorial. ---- END CONTENT --- + 3. **Run the script** -Doc-Content: https://wormhole.com/docs/products/messaging/overview/ ---- BEGIN CONTENT --- ---- -title: Messaging Overview -description: With Wormhole Messaging, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. -categories: Basics ---- + ```bash + npx tsx test/fetchGuardianSet.run.ts + ``` -# Messaging Overview + If successful, the output will be: -Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, multichain message-passing layer that enables secure, fast communication between blockchains. It solves the critical problem of blockchain isolation by allowing data and assets to move freely across networks, empowering developers to build true multichain applications. +
    +npx tsx test/fetchGuardianSet.run.ts + +Fetching current guardian set +Current Guardian Set Index: 4 +Guardian Addresses: [ + '0x5893b5a76c3f739645648885bdccc06cd70a3cd3', + '0xff6cb952589bde862c25ef4392132fb9d4a42157', + '0x114de8460193bdf3a2fcf81f86a09765f4762fd1', + '0x107a0086b32d7a0977926a205131d8731d39cbeb', + +...] + +
    -## Key Features + If an error occurs while fetching the Guardian set, a `500` status error will be logged. -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +### Replace Outdated Signatures -## How It Works +With the full VAA, Guardian signatures, and the latest Guardian set, we can now update outdated signatures while maintaining the required signature count. -The messaging flow consists of several core components: +1. **Create the `replaceSignatures()` function** - open `src/helpers/vaaHelper.ts` and add the function header. To catch and handle errors properly, all logic will be wrapped inside a `try` block -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic + ```typescript title="src/helpers/vaaHelper.ts" + vaa: string | Uint8Array, + observations: { guardianAddr: string; signature: string }[], + currentGuardians: string[], + guardianSetIndex: number +) { + console.log('Replacing Signatures...'); -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + try { + // Add logic in the following steps here + console.error('Unexpected error in replaceSignatures:', error); + } +} + ``` -## Use Cases + - **`vaa`** - original VAA bytes + - **`observations`** - observed signatures from the network + - **`currentGuardians`** - latest Guardian set + - **`guardianSetIndex`** - current Guardian set index -Wormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them. +2. **Validate input data** - ensure all required parameters are present before proceeding. If any required input is missing, the function throws an error to prevent execution with incomplete data. The Guardian set should never be empty; if it is, this likely indicates an error in fetching the Guardian set in a previous step -- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + ```typescript + if (currentGuardians.length === 0) + throw new Error('Guardian set is empty.'); + if (observations.length === 0) throw new Error('No observations provided.'); + ``` - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time +3. **Filter valid signatures** - remove signatures from inactive Guardians, keeping only valid ones. If there aren't enough valid signatures to replace the outdated ones, execution is halted to prevent an incomplete or invalid VAA -- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + ```typescript + currentGuardians.includes(sig.guardianAddr) + ); - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + if (validSigs.length === 0) + throw new Error('No valid signatures found. Cannot proceed.'); + ``` -- **Gas Abstraction** +4. **Convert valid signatures** - ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + ```typescript + .map((sig) => { + try { + const sigBuffer = Buffer.from(sig.signature, 'base64'); + // If it's 130 bytes, it's hex-encoded and needs conversion + const sigBuffer1 = + sigBuffer.length === 130 + ? Buffer.from(sigBuffer.toString(), 'hex') + : sigBuffer; -- **Bridging Intent Library** + const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); + const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); + const vRaw = sigBuffer1[64]; + const v = vRaw < 27 ? vRaw : vRaw - 27; - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + return { + guardianIndex: currentGuardians.indexOf(sig.guardianAddr), + signature: new Signature(r, s, v), + }; + } catch (error) { + console.error( + `Failed to process signature for guardian: ${sig.guardianAddr}`, + error + ); + return null; + } + }) + .filter( + (sig): sig is { guardianIndex: number; signature: Signature } => + sig !== null + ); // Remove null values + ``` -- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** +5. **Deserialize the VAA** - convert the raw VAA data into a structured format for further processing - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + ```typescript + try { + parsedVaa = deserialize('Uint8Array', vaa); + } catch (error) { + throw new Error(`Error deserializing VAA: ${error}`); + } + ``` -## Next Steps +6. **Identify outdated signatures** - compare the current VAA signatures with the newly formatted ones to detect which signatures belong to outdated Guardians. Remove these outdated signatures to ensure only valid ones remain -Follow these steps to work with Wormhole Messaging: + ```typescript + .filter( + (vaaSig) => + !formattedSigs.some( + (sig) => sig.guardianIndex === vaaSig.guardianIndex + ) + ) + .map((sig) => sig.guardianIndex); -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure ---- END CONTENT --- + console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ ---- BEGIN CONTENT --- ---- -title: Create Cross-Chain Contracts -description: Learn how to create cross-chain contracts using Wormhole's Solidity SDK. Deploy contracts on Avalanche and Celo Testnets and send messages across chains. ---- + let updatedSignatures = parsedVaa.signatures.filter( + (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) + ); + ``` -# Create Cross-Chain Messaging Contracts +7. **Replace outdated signatures** - substitute outdated signatures with valid ones while maintaining the correct number of signatures. If there aren’t enough valid replacements, execution stops -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank} + ```typescript + (sig) => + !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) + ); -## Introduction + // Check if we have enough valid signatures to replace outdated ones** + if (outdatedGuardianIndexes.length > validReplacements.length) { + console.warn( + `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` + ); + return; + } -Wormhole's cross-chain messaging allows smart contracts to interact seamlessly across multiple blockchains. This enables developers to build decentralized applications that leverage the strengths of different networks, whether it's Avalanche, Celo, Ethereum, or beyond. In this tutorial, we'll explore using [Wormhole's Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} to create cross-chain contracts to send and receive messages across chains. + updatedSignatures = [ + ...updatedSignatures, + ...validReplacements.slice(0, outdatedGuardianIndexes.length), + ]; -Wormhole's messaging infrastructure simplifies data transmission, event triggering, and transaction initiation across blockchains. In this tutorial, we'll guide you through a simple yet powerful hands-on demonstration that showcases this practical capability. We'll deploy contracts on two Testnets—Avalanche Fuji and Celo Alfajores—and send messages from one chain to another. This tutorial is perfect for those new to cross-chain development and seeking hands-on experience with Wormhole's powerful toolkit. + updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); + ``` -By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. +8. **Serialize the updated VAA** - reconstruct the VAA with the updated signatures and convert it into a format suitable for submission -This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. + ```typescript + ...parsedVaa, + guardianSet: guardianSetIndex, + signatures: updatedSignatures, + }; -## Wormhole Overview + let patchedVaa: Uint8Array; + try { + patchedVaa = serialize(updatedVaa); + } catch (error) { + throw new Error(`Error serializing updated VAA: ${error}`); + } + ``` -We'll interact with two key Wormhole components: the [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} and the [Wormhole Core Contracts](/docs/protocol/infrastructure/core-contracts/){target=\_blank}. The relayer handles cross-chain message delivery and ensures the message is accurately received on the target chain. This allows smart contracts to communicate across blockchains without developers worrying about the underlying complexity. +9. **Send the updated VAA for verification and handle errors** - submit the updated VAA to an Ethereum RPC node for validation, ensuring it can be proposed for Guardian approval. If an error occurs during submission or signature replacement, log the issue and prevent further execution -Additionally, we'll rely on the Wormhole relayer to automatically determine cross-chain transaction costs and facilitate payments. This feature simplifies cross-chain development by allowing you to specify only the target chain and the message. The relayer handles the rest, ensuring that the message is transmitted with the appropriate fee. + ```typescript + if (!(patchedVaa instanceof Uint8Array)) + throw new Error('Patched VAA is not a Uint8Array!'); -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) + const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; -## Prerequisites + console.log('Sending updated VAA to RPC...'); -Before starting this tutorial, ensure you have the following: + const result = await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), + }, + 'latest', + ], + }); -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts -- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees -- Wallet private key + const verificationResult = result.data.result; + console.log('Updated VAA (hex):', vaaHex); + return verificationResult; + } catch (error) { + throw new Error(`Error sending updated VAA to RPC: ${error}`); + } + ``` -## Build Cross-Chain Messaging Contracts +???- code "Complete Function" + ```typescript + vaa: string | Uint8Array, + observations: { guardianAddr: string; signature: string }[], + currentGuardians: string[], + guardianSetIndex: number +) { + console.log('Replacing Signatures...'); -In this section, we'll deploy two smart contracts: one to send a message from Avalanche Fuji and another to receive it on Celo Alfajores. The contracts interact with the Wormhole relayer to transmit messages across chains. + try { + if (!vaa) throw new Error('VAA is undefined or empty.'); + if (currentGuardians.length === 0) + throw new Error('Guardian set is empty.'); + if (observations.length === 0) throw new Error('No observations provided.'); -At a high level, our contracts will: + const validSigs = observations.filter((sig) => + currentGuardians.includes(sig.guardianAddr) + ); -1. Send a message from Avalanche to Celo using the Wormhole relayer -2. Receive and process the message on Celo, logging the content of the message + if (validSigs.length === 0) + throw new Error('No valid signatures found. Cannot proceed.'); -Before diving into the deployment steps, let's first break down key parts of the contracts. + const formattedSigs = validSigs + .map((sig) => { + try { + const sigBuffer = Buffer.from(sig.signature, 'base64'); + // If it's 130 bytes, it's hex-encoded and needs conversion + const sigBuffer1 = + sigBuffer.length === 130 + ? Buffer.from(sigBuffer.toString(), 'hex') + : sigBuffer; -### Sender Contract: MessageSender + const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); + const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); + const vRaw = sigBuffer1[64]; + const v = vRaw < 27 ? vRaw : vRaw - 27; -The `MessageSender` contract is responsible for quoting the cost of sending a message cross-chain and then sending that message. + return { + guardianIndex: currentGuardians.indexOf(sig.guardianAddr), + signature: new Signature(r, s, v), + }; + } catch (error) { + console.error( + `Failed to process signature for guardian: ${sig.guardianAddr}`, + error + ); + return null; + } + }) + .filter( + (sig): sig is { guardianIndex: number; signature: Signature } => + sig !== null + ); // Remove null values -Key functions include: + let parsedVaa: VAA<'Uint8Array'>; + try { + parsedVaa = deserialize('Uint8Array', vaa); + } catch (error) { + throw new Error(`Error deserializing VAA: ${error}`); + } - - **`quoteCrossChainCost`** - calculates the cost of delivering a message to the target chain using the Wormhole relayer - - **`sendMessage`** - encodes the message and sends it to the target chain and contract address using the Wormhole relayer + const outdatedGuardianIndexes = parsedVaa.signatures + .filter( + (vaaSig) => + !formattedSigs.some( + (sig) => sig.guardianIndex === vaaSig.guardianIndex + ) + ) + .map((sig) => sig.guardianIndex); -Here's the core of the contract: + console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); -```solidity -uint16 targetChain, - address targetAddress, - string memory message - ) external payable { - uint256 cost = quoteCrossChainCost(targetChain); + let updatedSignatures = parsedVaa.signatures.filter( + (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) + ); - require( - msg.value >= cost, - "Insufficient funds for cross-chain delivery" - ); + const validReplacements = formattedSigs.filter( + (sig) => + !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) + ); - wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(message, msg.sender), - 0, - GAS_LIMIT - ); + // Check if we have enough valid signatures to replace outdated ones** + if (outdatedGuardianIndexes.length > validReplacements.length) { + console.warn( + `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` + ); + return; } -``` - -You can find the full code for the `MessageSender.sol` below. -??? code "MessageSender.sol" - - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; + updatedSignatures = [ + ...updatedSignatures, + ...validReplacements.slice(0, outdatedGuardianIndexes.length), + ]; -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; + updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); -contract MessageSender { - IWormholeRelayer public wormholeRelayer; - uint256 constant GAS_LIMIT = 50000; + const updatedVaa: VAA<'Uint8Array'> = { + ...parsedVaa, + guardianSet: guardianSetIndex, + signatures: updatedSignatures, + }; - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + let patchedVaa: Uint8Array; + try { + patchedVaa = serialize(updatedVaa); + } catch (error) { + throw new Error(`Error serializing updated VAA: ${error}`); } - function quoteCrossChainCost( - uint16 targetChain - ) public view returns (uint256 cost) { - (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); - } + try { + if (!(patchedVaa instanceof Uint8Array)) + throw new Error('Patched VAA is not a Uint8Array!'); - function sendMessage( - uint16 targetChain, - address targetAddress, - string memory message - ) external payable { - uint256 cost = quoteCrossChainCost(targetChain); + const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; - require( - msg.value >= cost, - "Insufficient funds for cross-chain delivery" - ); + console.log('Sending updated VAA to RPC...'); - wormholeRelayer.sendPayloadToEvm{value: cost}( - targetChain, - targetAddress, - abi.encode(message, msg.sender), - 0, - GAS_LIMIT - ); + const result = await axios.post(RPC, { + jsonrpc: '2.0', + id: 1, + method: 'eth_call', + params: [ + { + from: null, + to: ETH_CORE, + data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), + }, + 'latest', + ], + }); + + const verificationResult = result.data.result; + console.log('Updated VAA (hex):', vaaHex); + return verificationResult; + } catch (error) { + throw new Error(`Error sending updated VAA to RPC: ${error}`); } + } catch (error) { + console.error('Unexpected error in replaceSignatures:', error); + } } ``` -### Receiver Contract: MessageReceiver +## Create Script to Replace Outdated VAA Signatures -The `MessageReceiver` contract handles incoming cross-chain messages. When a message arrives, it decodes the payload and logs the message content. It ensures that only authorized contracts can send and process messages, adding an extra layer of security in cross-chain communication. +Now that we have all the necessary helper functions, we will create a script to automate replacing outdated VAA signatures. This script will retrieve a transaction’s VAA sequentially, check its validity, fetch the latest Guardian set, and update its signatures. By the end, it will output a correctly signed VAA that can be proposed for Guardian approval. -#### Emitter Validation and Registration +1. **Open the file** - inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs -In cross-chain messaging, validating the sender is essential to prevent unauthorized contracts from sending messages. The `isRegisteredSender` modifier ensures that messages can only be processed if they come from the registered contract on the source chain. This guards against malicious messages and enhances security. + ```typescript title="src/scripts/replaceSignatures.ts" + fetchVaaId, + fetchVaa, + checkVaaValidity, + fetchObservations, + fetchGuardianSet, + replaceSignatures, +} from '../helpers/vaaHelper'; +import { TXS } from '../config/constants'; + ``` -Key implementation details include: - - - **`registeredSender`** - stores the address of the registered sender contract - - **`setRegisteredSender`** - registers the sender's contract address on the source chain. It ensures that only registered contracts can send messages, preventing unauthorized senders - - **`isRegisteredSender`** - restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication +2. **Define the main execution function** - add the following function inside `src/scripts/replaceSignatures.ts` to process each transaction in `TXS`, going step by step through the signature replacement process -```solidity + ```typescript + try { + for (const tx of TXS) { + console.log(`\nProcessing TX: ${tx}\n`); -require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } + // 1. Fetch Transaction VAA IDs: + const vaaIds = await fetchVaaId([tx]); + if (!vaaIds.length) continue; - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } -``` + // 2. Fetch VAA Data: + const vaaData = await fetchVaa(vaaIds); + if (!vaaData.length) continue; -#### Message Processing + const vaaBytes = vaaData[0].vaaBytes; + if (!vaaBytes) continue; -The `receiveWormholeMessages` is the core function that processes the received message. It checks that the Wormhole relayer sent the message, decodes the payload, and emits an event with the message content. It is essential to verify the message sender to prevent unauthorized messages. + // 3. Check VAA Validity: + const { valid } = await checkVaaValidity(vaaBytes); + if (valid) continue; -```solidity -bytes memory payload, - bytes[] memory, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 - ) public payable override isRegisteredSender(sourceChain, sourceAddress) { - require( - msg.sender == address(wormholeRelayer), - "Only the Wormhole relayer can call this function" - ); + // 4. Fetch Observations (VAA signatures): + const observations = await fetchObservations(vaaIds[0]); - // Decode the payload to extract the message - string memory message = abi.decode(payload, (string)); + // 5. Fetch Current Guardian Set: + const [currentGuardians, guardianSetIndex] = await fetchGuardianSet(); - // Example use of sourceChain for logging - if (sourceChain != 0) { - emit SourceChainLogged(sourceChain); - } + // 6. Replace Signatures: + const response = await replaceSignatures( + Buffer.from(vaaBytes, 'base64'), + observations, + currentGuardians, + guardianSetIndex + ); - // Emit an event with the received message - emit MessageReceived(message); + if (!response) continue; } -``` - -You can find the full code for the `MessageReceiver.sol` below. - -??? code "MessageReceiver.sol" + } catch (error) { + console.error('❌ Error in execution:', error); + process.exit(1); + } +} + ``` - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.18; +3. **Make the script executable** - ensure it runs when executed -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol"; + ```typescript + + ``` -contract MessageReceiver is IWormholeReceiver { - IWormholeRelayer public wormholeRelayer; - address public registrationOwner; + To run the script, use the following command: - // Mapping to store registered senders for each chain - mapping(uint16 => bytes32) public registeredSenders; + ```bash + npx tsx src/scripts/replaceSignatures.ts + ``` - event MessageReceived(string message); - event SourceChainLogged(uint16 sourceChain); +
    +npx tsx src/scripts/replaceSignatures.ts + +Processing TX: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 +❌ VAA Valid: false, Reason: VM signature invalid +Fetching observations +Fetching current guardian set +Replacing Signatures... +Outdated Guardian Indexes: [ 0 ] +Sending updated VAA to RPC... +Updated VAA (hex): 0x01000000040d010019447b72d51e33923a3d6b28496ccd3722d5f1e33e2... + +
    - constructor(address _wormholeRelayer) { - wormholeRelayer = IWormholeRelayer(_wormholeRelayer); - registrationOwner = msg.sender; // Set contract deployer as the owner - } +The script logs each step, skipping valid VAAs, replacing outdated signatures for invalid VAAs, and logging any errors. It then completes with a valid VAA ready for submission. - modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { - require( - registeredSenders[sourceChain] == sourceAddress, - "Not registered sender" - ); - _; - } +## Resources - function setRegisteredSender( - uint16 sourceChain, - bytes32 sourceAddress - ) public { - require( - msg.sender == registrationOwner, - "Not allowed to set registered sender" - ); - registeredSenders[sourceChain] = sourceAddress; - } +You can explore the complete project and find all necessary scripts and configurations in Wormhole's [demo GitHub repository](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank}. - // Update receiveWormholeMessages to include the source address check - function receiveWormholeMessages( - bytes memory payload, - bytes[] memory, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 - ) public payable override isRegisteredSender(sourceChain, sourceAddress) { - require( - msg.sender == address(wormholeRelayer), - "Only the Wormhole relayer can call this function" - ); +The demo repository includes a bonus script to check the VAA redemption status on Ethereum and Solana, allowing you to verify whether a transaction has already been redeemed on the destination chain. - // Decode the payload to extract the message - string memory message = abi.decode(payload, (string)); +## Conclusion - // Example use of sourceChain for logging - if (sourceChain != 0) { - emit SourceChainLogged(sourceChain); - } +You've successfully built a script to fetch, validate, and replace outdated signatures in VAAs using Wormholescan and the Wormhole SDK. - // Emit an event with the received message - emit MessageReceived(message); - } -} - ``` +It's important to note that this tutorial does not update VAAs in the Wormhole network. Before redeeming the VAA, you must propose it for Guardian approval to finalize the process. +--- END CONTENT --- -## Deploy Contracts +Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: MultiGov Architecture +description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. +categories: MultiGov +--- -This section will guide you through deploying the cross-chain messaging contracts on the Avalanche Fuji and Celo Alfajores Testnets. Follow these steps to get your contracts up and running. +# MultiGov Architecture -### Deployment Tools -We use _Foundry_ to deploy our smart contracts. However, you can use any tool you're comfortable with, such as: +MultiGov uses a hub-and-spoke architecture to coordinate governance across multiple blockchains. The hub chain is the central controller that handles proposal creation, vote aggregation, and execution. Spoke chains allow token holders to vote locally and can also execute proposal outcomes specific to their network. - - [Remix](https://remix.ethereum.org/){target=\_blank} for a browser-based IDE - - [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#installation){target=\_blank} for a more extensive JavaScript/TypeScript workflow - - [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for a CLI-focused experience with built-in scripting and testing features +Wormhole’s multichain messaging infrastructure connects the hub and spokes, enabling secure and efficient chain communication. This design allows DAOs to operate seamlessly across ecosystems while maintaining a unified governance process. -The contracts and deployment steps remain the same regardless of your preferred tool. The key is to ensure you have the necessary Testnet funds and are deploying to the right networks. +The diagram below illustrates this high-level architecture. -### Repository Setup +![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/architecture-1.webp) -To get started with cross-chain messaging using Wormhole, first clone the [GitHub repository](https://github.com/wormhole-foundation/demo-wormhole-messaging){target=\_blank}. This repository includes everything you need to deploy, interact, and test the message flow between chains. +## Key Components -This demo focuses on using the scripts, so it's best to take a look at them, starting with `deploySender.ts`, `deployReceiver.ts`, and `sendMessage.ts`. +### Hub Chain Contracts -To configure the dependencies properly, run the following command: +The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. -```bash -npm install -``` + - **`HubGovernor`** - central governance contract managing proposals and vote tallying + - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` + - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains + - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed + - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals + - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible -The repository includes: +### Spoke Chains Contracts -- Two Solidity contracts: +Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. - - **`MessageSender.sol`** - contract that sends the cross-chain message from Avalanche - - **`MessageReceiver.sol`** - contract that receives the cross-chain message on Celo + - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub + - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub + - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters + - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury -- Deployment scripts located in the `script` directory: +### Spoke Solana Staking Program - - **`deploySender.ts`** - deploys the `MessageSender` contract to Avalanche - - **`deployReceiver.ts`** - deploys the `MessageReceiver` contract to Celo - - **`sendMessage.ts`** - sends a message from Avalanche to Celo +The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. -- Configuration files and ABI JSON files for easy deployment and interaction: +The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: - - **`chains.json`** - configuration file that stores key information for the supported Testnets, including the Wormhole relayer addresses, RPC URLs, and chain IDs. You likely won't need to modify this file unless you're working with different networks + - **`GlobalConfig`** - global program configuration + - **`StakeAccountMetadata`** - stores user's staking information + - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts + - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens + - **`CheckpointData`** - tracks delegation history + - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain + - **`GuardianSignatures`** - stores guardian signatures for message verification + - **`ProposalData`** - stores data about a specific proposal, including votes and start time + - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal + - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol + - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution + - **`VestingBalance`** - stores total vesting balance and related staking information of a vester + - **`VestingConfig`** - defines vesting configuration, including mint and admin details + - **`Vesting`** - represents individual vesting allocations with maturation data + - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows - - A dedicated `interfaces` directory inside the `src` folder for TypeScript type definitions: +Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. - - **`ChainsConfig.ts`** - defines the types for the `chains.json` configuration file - - **`DeployedContracts.ts`** - contains types for deployed contract addresses and related information - - **`MessageJsons.ts`** - includes types for ABI and bytecode JSONs used by the deployment scripts - - **`index.ts`** - serves as an export aggregator for the interfaces, simplifying imports in other files +## System Workflow -### Important Setup Steps +The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. -1. **Add your private key** - create a `.env` file in the root of the project and add your private key: - - ```env - touch .env - ``` +### EVM Governance Workflow - Inside `.env`, add your private key in the following format: +The EVM-based MultiGov workflow follows these steps: - ```env - PRIVATE_KEY=INSERT_PRIVATE_KEY - ``` +1. **Proposal creation**: + 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method + 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold +2. **Proposal metadata distribution**: + 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` + 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details +3. **Voting process**: + 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` + 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole + 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution + 3. After the timelock delay, the proposal can be executed on the hub chain + 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains + 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` -2. **Compile the contracts** - ensure everything is set up correctly by compiling the contracts: +### Solana Governance Workflow - ```bash - forge build - ``` +The Solana-based MultiGov workflow follows these steps: -The expected output should be similar to this: +1. **Proposal creation**: + 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold + 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function + 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution -
    -forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
    +2. **Proposal metadata distribution**: + 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** + 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program + 3. The proposal data is verified to ensure it matches the expected format + 4. Guardian signatures are posted using the `PostSignatures` instruction + 5. Once validated, the proposal is stored on-chain -### Deployment Process +3. **Voting process**: + 1. Users vote on proposals stored in the `ProposalData` account on Solana + 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) + 3. Eligibility and vote weight are verified using historical voter checkpoint data + 4. A **Query Wormhole** request retrieves vote data from a Solana PDA + 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification + 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision -Both deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the following key tasks: +4. **Vote tallying and proposal execution**: + 1. `HubGovernor` tallies votes from all chains + 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution + 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain + 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana + 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions -1. **Load configuration and contract details** - each script begins by loading the necessary configuration details, such as the network's RPC URL and the contract's ABI and bytecode. This information is essential for deploying the contract to the correct blockchain network +## Cross-Chain Communication - === "`chains.json`" +MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. - ```json - { - "chains": [ - { - "description": "Avalanche testnet fuji", - "chainId": 6, - "rpc": "https://api.avax-test.network/ext/bc/C/rpc", - "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", - "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", - "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" - }, - { - "description": "Celo Testnet", - "chainId": 14, - "rpc": "https://alfajores-forno.celo-testnet.org", - "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", - "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", - "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" - } - ] -} - ``` +## Security Measures - === "`deploySender.ts`" +- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting + - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions +- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review +- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol - ```typescript - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +## Detailed Architecture Diagram - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); - ``` +This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. - === "`deployReceiver.ts`" + +![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp) +--- END CONTENT --- - ```typescript - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ +--- BEGIN CONTENT --- +--- +title: MultiGov FAQs +description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. +categories: MultiGov +--- - // Get the Celo Testnet configuration - const celoChain = chains.chains.find((chain) => - chain.description.includes('Celo Testnet') - ); - ``` +# FAQs - !!! note - The `chains.json` file contains the configuration details for the Avalanche Fuji and Celo Alfajores Testnets. You can modify this file to add more networks if needed. For a complete list of contract addresses, visit the [reference page](/docs/products/reference/contract-addresses/){target=\_blank}. +## What is MultiGov? -2. **Set up provider and wallet** - the scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction +MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. - === "`deploySender.ts`" +## How does MultiGov ensure security in cross-chain communication? - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: - === "`deployReceiver.ts`" +- Message origin verification to prevent unauthorized governance actions +- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states +- Authorized participant validation to maintain the integrity of the governance process +- Replay attack prevention by tracking executed messages - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +## Can MultiGov integrate with any blockchain? -3. **Deploy the contract** - the contract is deployed to the network specified in the configuration. Upon successful deployment, the contract address is returned, which is crucial for interacting with the contract later on +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. - === "`deploySender.ts`" +## How are votes aggregated across different chains? - ```typescript - avalancheChain.wormholeRelayer - ); - await senderContract.waitForDeployment(); - ``` +Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. - === "`deployReceiver.ts`" +## Can governance upgrade from a single chain to MultiGov? - ```typescript - celoChain.wormholeRelayer - ); - await receiverContract.waitForDeployment(); - ``` +Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. -4. **Register the `MessageSender` on the target chain** - after you deploy the `MessageReceiver` contract on the Celo Alfajores network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed +## How can I create a proposal in MultiGov? - This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract +Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. - ```typescript - const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; - if (!avalancheSenderAddress) { - throw new Error('Avalanche MessageSender address not found.'); - } +## How do I vote on a proposal if I hold tokens on a spoke chain? - // Define the source chain ID for Avalanche Fuji - const sourceChainId = 6; +You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. - // Call setRegisteredSender on the MessageReceiver contract - const tx = await (receiverContract as any).setRegisteredSender( - sourceChainId, - ethers.zeroPadValue(avalancheSenderAddress, 32) - ); - await tx.wait(); - ``` +## How are approved proposals executed across multiple chains? -You can find the full code for the `deploySender.ts` and `deployReceiver.ts` below. +When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. -??? code "deploySender.ts" +## What are the requirements for using MultiGov? - ```typescript - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { - ChainsConfig, - DeployedContracts, - MessageSenderJson, -} from './interfaces'; +To use MultiGov, your DAO must meet the following requirements: -dotenv.config(); +- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance +- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature -async function main(): Promise { - // Load the chain configuration from JSON - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +## What do I need to set up MultiGov for my project? - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); - if (!avalancheChain) { - throw new Error( - 'Avalanche testnet configuration not found in chains.json.' - ); - } +Get started by filling out the form below: - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); +https://www.tally.xyz/get-started - // Load the ABI and bytecode of the MessageSender contract - const messageSenderJson: MessageSenderJson = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); +Tally will reach out to help get your DAO set up with MultiGov. - const { abi, bytecode } = messageSenderJson; +To set up testing MultiGov for your DAO, you'll need: - // Create a ContractFactory for MessageSender - const MessageSender = new ethers.ContractFactory(abi, bytecode, wallet); +- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed +- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) +- Modify and deploy the hub and spoke contracts using the provided scripts +- Set up the necessary environment variables and configurations - // Deploy the contract using the Wormhole Relayer address for Avalanche Fuji - const senderContract = await MessageSender.deploy( - avalancheChain.wormholeRelayer - ); - await senderContract.waitForDeployment(); +## Can MultiGov be used with non-EVM chains? - console.log('MessageSender deployed to:', senderContract.target); // `target` is the address in ethers.js v6 +The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. - // Update the deployedContracts.json file - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/deployedContracts.json' - ); - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); +## How can I customize voting parameters in MultiGov? - deployedContracts.avalanche = { - MessageSender: senderContract.target as any, - deployedAt: new Date().toISOString(), - }; +Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); -} +Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +## How does MultiGov handle potential network issues or temporary chain unavailability? -??? code "deployReceiver.ts" +MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: - ```typescript - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { - ChainsConfig, - DeployedContracts, - MessageReceiverJson, -} from './interfaces'; +1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable +2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems +3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through +4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline -dotenv.config(); +However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. -async function main(): Promise { - // Load the chain configuration from the JSON file - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +## How does MultiGov differ from traditional DAO governance? - // Get the Celo Testnet configuration - const celoChain = chains.chains.find((chain) => - chain.description.includes('Celo Testnet') - ); - if (!celoChain) { - throw new Error('Celo Testnet configuration not found.'); - } +Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(celoChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); +## What are the main components of MultiGov? - // Load the ABI and bytecode of the MessageReceiver contract - const messageReceiverJson: MessageReceiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/MessageReceiver.sol/MessageReceiver.json' - ), - 'utf8' - ) - ); +The main components of MultiGov include: - const { abi, bytecode } = messageReceiverJson; +- **Hub chain** - central coordination point for governance activities +- **Spoke chains** - additional chains where token holders can participate in governance +- **Wormhole integration** - enables secure cross-chain message passing +- **Governance token** - allows holders to participate in governance across all integrated chains +--- END CONTENT --- - // Create a ContractFactory for MessageReceiver - const MessageReceiver = new ethers.ContractFactory(abi, bytecode, wallet); +Doc-Content: https://wormhole.com/docs/products/multigov/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Multigov +description: Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. +categories: MultiGov +--- - // Deploy the contract using the Wormhole Relayer address for Celo Testnet - const receiverContract = await MessageReceiver.deploy( - celoChain.wormholeRelayer - ); - await receiverContract.waitForDeployment(); +# Get Started with Multigov - console.log('MessageReceiver deployed to:', receiverContract.target); // `target` is the contract address in ethers.js v6 +## Introduction - // Update the deployedContracts.json file - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/deployedContracts.json' - ); - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); +[MultiGov](/docs/products/multigov/overview/){target=\_blank} enables multichain governance using Wormhole messaging. With MultiGov, token holders can create proposals, vote, and execute decisions from any supported chain, eliminating the need to bridge assets or rely on a single governance hub. - // Retrieve the address of the MessageSender from the deployedContracts.json file - const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender; - if (!avalancheSenderAddress) { - throw new Error('Avalanche MessageSender address not found.'); - } +This page walks you through the MultiGov deployment flow—from requesting access with Tally to choosing a network and following the appropriate deployment guide. - // Define the source chain ID for Avalanche Fuji - const sourceChainId = 6; +## Prerequisites - // Call setRegisteredSender on the MessageReceiver contract - const tx = await (receiverContract as any).setRegisteredSender( - sourceChainId, - ethers.zeroPadValue(avalancheSenderAddress, 32) - ); - await tx.wait(); +Before deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL): - console.log( - `Registered MessageSender (${avalancheSenderAddress}) for Avalanche chain (${sourceChainId})` - ); +- **EVM chains**: + - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\_blank} standard + - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting - deployedContracts.celo = { - MessageReceiver: receiverContract.target as any, - deployedAt: new Date().toISOString(), - }; +- **Solana**: + - Use an SPL token + - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\_blank} - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); -} +## Request Tally Access -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +MultiGov integrations are coordinated through [Tally](https://www.tally.xyz/explore){target=\_blank}, a multichain governance platform that powers proposal creation, voting, and execution. -### Deploy the Sender Contract +To get started, fill out the integration [intake form](https://www.tally.xyz/get-started){target=\_blank}. The Tally team will review your application and contact you to discuss deployment and setup requirements. -The sender contract will handle quoting and sending messages cross-chain. +Once approved, review the deployment flow below to understand the integration process. Then, follow the appropriate deployment guide to integrate MultiGov with your governance token on EVM chains, Solana, or other supported networks. -1. Run the following command to deploy the sender contract: +## Deployment Flow - ```bash - npm run deploy:sender - ``` +MultiGov deployments follow a similar structure on both EVM and Solana. This section provides a high-level overview of the end-to-end flow. Each step is explained in more detail in the platform-specific deployment guides linked [below](#next-steps). -2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\_blank} +[timeline(wormhole-docs/.snippets/text/products/multigov/deployment-flow-timeline.json)] -
    -npm run deploy:sender - > wormhole-cross-chain@1.0.0 deploy:sender - > node script/deploySender.ts - MessageSender deployed to: 0xf5c474f335fFf617fA6FD04DCBb17E20ee0cEfb1 - -
    +## Next Steps +You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: -### Deploy the Receiver Contract + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation +--- END CONTENT --- -The receiver contract listens for cross-chain messages and logs them when received. +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ +--- BEGIN CONTENT --- +--- +title: Deploy MultiGov on EVM Chains +description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. +categories: MultiGov +--- -1. Deploy the receiver contract with this command: - - ```bash - npm run deploy:receiver - ``` +# Deploy MultiGov on EVM Chains -2. After deployment, note down the contract address. You may check the contract on the [Celo Alfajores Explorer](https://alfajores.celoscan.io/){target=\_blank}. +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. +Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. -## Send a Cross-Chain Message +## Prerequisites -Now that both the sender and receiver contracts are deployed, let's move on to the next exciting step: sending a cross-chain message from Avalanche Fuji to Celo Alfajores. +To interact with MultiGov, you'll need the following: -In this example, we will use the `sendMessage.ts` script to transmit a message from the sender contract on Avalanche to the receiver contract on Celo. The script uses [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} to interact with the deployed contracts, calculate the cross-chain cost dynamically, and handle the transaction. +- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} +- Install [Git](https://git-scm.com/downloads){target=\_blank} +- Clone the repository: + ```bash + git clone https://github.com/wormhole-foundation/multigov + cd evm # for evm testing/deploying + ``` -Let's break down the script step by step. +## Development Setup -1. **Load configuration files** +For developers looking to set up a local MultiGov environment: - 1. **`chains.json`** - contains details about the supported Testnet chains, such as RPC URLs and relayer addresses - 2. **`deployedContracts.json`** - stores the addresses of the deployed sender and receiver contracts. This file is dynamically updated when contracts are deployed, but users can also manually add their own deployed contract addresses if needed +1. Install dependencies: + ```bash + forge install + ``` - ```typescript - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +2. Set up environment variables: + ```bash + cp .env.example .env + ``` - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/deployedContracts.json'), - 'utf8' - ) - ); - ``` + Edit `.env` with your specific [configuration](#configuration){target=\_blank} -2. **Configure the provider and signer** - the script first reads the chain configurations and extracts the contract addresses. One essential step in interacting with a blockchain is setting up a _provider_. A provider is your connection to the blockchain network. It allows your script to interact with the blockchain, retrieve data, and send transactions. In this case, we're using a JSON-RPC provider +3. Compile contracts: + ```bash + forge build + ``` - Next, we configure the wallet, which will be used to sign transactions. The wallet is created using the private key and the provider. This ensures that all transactions sent from this wallet are broadcast to the Avalanche Fuji network: - - ```typescript - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); - ``` +4. Deploy contracts (example for Sepolia testnet): - After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it: + For hub chains: + ```bash + forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast + ``` - ```typescript - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); + For spoke chains (e.g., Optimism Sepolia): + ```bash + forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast ``` -3. **Set up the message details** - the next part of the script defines the target chain (Celo) and the target address (the receiver contract on Celo): +## Configuration - ```typescript - const targetAddress = deployedContracts.celo.MessageReceiver; - ``` +When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: - You can customize the message that will be sent across chains: +### Hub Governor Key Parameters - ```typescript - - ``` +- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day +- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal +- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful +- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day -4. **Estimate cross-chain cost** - before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function: + !!! note + This helps mitigate cross-chain double voting. - ```typescript - - ``` +### Hub Proposal Extender Key Parameters - This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message. +- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours +- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour -5. **Send a message** - with everything set up, the message is sent using the `sendMessage` function: +### Spoke Vote Aggregator Key Parameters - ```typescript - targetChain, - targetAddress, - message, - { - value: txCost, - } - ); - ``` +- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day - After sending, the script waits for the transaction to be confirmed: + !!! note + This is crucial for mitigating cross-chain double voting - ```typescript - - ``` +### Hub Evm Spoke Vote Aggregator Key Parameters -6. **Run the script** - to send the message, run the following command: +- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes - ```bash - npm run send:message - ``` +### Updateable Governance Parameters -If everything is set up correctly, the message will be sent from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. You can monitor the transaction and verify that the message was received on Celo using the [Wormhole Explorer](https://wormholescan.io/#/?network=TESTNET){target=\_blank}. +The following key parameters can be updated through governance proposals: -The console should output something similar to this: +- `votingDelay` - delay before voting starts (in seconds) +- `votingPeriod` - duration of the voting period (in seconds) +- `proposalThreshold` - threshold for creating proposals (in tokens) +- `quorum` - number of votes required for quorum +- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) +- `voteWeightWindow` - window for vote weight checkpoints (in seconds) +- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time -
    -npm run send:message - > wormhole-cross-chain@1.0.0 send:message - > node script/sendMessage.ts -Sender Contract Address: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 -Receiver Contract Address: 0x692550997C252cC5044742D1A2BD91E4f4b46D39 -... -Transaction sent, waiting for confirmation... -... -Message sent! Transaction hash: - 0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6 -You may see the transaction status on the Wormhole Explorer: - https://wormholescan.io/#/tx/0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6?network=TESTNET - -
    +These parameters can be queried using their respective getter functions on the applicable contract. -You can find the full code for the `sendMessage.ts` below. +To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. +--- END CONTENT --- -??? code "sendMessage.ts" +Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: MultiGov Deployment to Solana +description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. +categories: MultiGov +--- - ```solidity - import { ethers } from 'ethers'; -import fs from 'fs'; -import path from 'path'; -import dotenv from 'dotenv'; -import { ChainsConfig, DeployedContracts } from './interfaces'; +# Deploy MultiGov on Solana -dotenv.config(); +This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. -async function main(): Promise { - // Load the chain configuration and deployed contract addresses - const chains: ChainsConfig = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/chains.json'), - 'utf8' - ) - ); +Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. - const deployedContracts: DeployedContracts = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../deploy-config/deployedContracts.json'), - 'utf8' - ) - ); +## Prerequisites - console.log( - 'Sender Contract Address: ', - deployedContracts.avalanche.MessageSender - ); - console.log( - 'Receiver Contract Address: ', - deployedContracts.celo.MessageReceiver - ); - console.log('...'); +To deploy MultiGov on Solana, ensure you have the following installed: - // Get the Avalanche Fuji configuration - const avalancheChain = chains.chains.find((chain) => - chain.description.includes('Avalanche testnet') - ); + - Install [Git](https://git-scm.com/downloads){target=\_blank} + - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** + - Install [Solana CLI](https://docs.anza.xyz/cli/install/){target=\_blank} **`v1.18.20`** + - Install [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`v0.30.1`** + - Install [Rust](https://www.rust-lang.org/tools/install){target=\_blank} **`v1.80.1`** + - Install [Docker](https://www.docker.com/get-started/){target=\_blank} + - Clone the repository: + ```bash + git clone https://github.com/wormhole-foundation/multigov.git + cd multigov/solana/ + ``` - if (!avalancheChain) { - throw new Error( - 'Avalanche testnet configuration not found in chains.json.' - ); - } +## Build the Project - // Set up the provider and wallet - const provider = new ethers.JsonRpcProvider(avalancheChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider); +To create a verifiable build of the MultiGov Staking Program, run the following command: - // Load the ABI of the MessageSender contract - const messageSenderJson = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'), - 'utf8' - ) - ); +```bash +./scripts/build_verifiable_staking_program.sh +``` - const abi = messageSenderJson.abi; +Once the build is complete, the compiled artifacts will be available in the `target` folder. - // Create a contract instance for MessageSender - const MessageSender = new ethers.Contract( - deployedContracts.avalanche.MessageSender, // Automatically use the deployed address - abi, - wallet - ); +## Set Up the Deployer Account - // Define the target chain and target address (the Celo receiver contract) - const targetChain = 14; // Wormhole chain ID for Celo Alfajores - const targetAddress = deployedContracts.celo.MessageReceiver; +For a successful deployment, you need a funded deployer account on Solana. This account will store the program and execute deployment transactions. - // The message you want to send - const message = 'Hello from Avalanche to Celo!'; +In this section, you will create a new keypair, check the account balance, and ensure it has enough SOL tokens to cover deployment costs. If needed, you can fund the account using different methods before deploying. - // Dynamically quote the cross-chain cost - const txCost = await MessageSender.quoteCrossChainCost(targetChain); +### Generate a New Keypair - // Send the message (make sure to send enough gas in the transaction) - const tx = await MessageSender.sendMessage( - targetChain, - targetAddress, - message, - { - value: txCost, - } - ); +To create a new keypair and save it to a file, run the following command: - console.log('Transaction sent, waiting for confirmation...'); - await tx.wait(); - console.log('...'); +```bash +solana-keygen new --outfile ./app/keypairs/deployer.json +``` - console.log('Message sent! Transaction hash:', tx.hash); - console.log( - `You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/${tx.hash}?network=TESTNET` - ); -} +### Check the Deployer Account Address -main().catch((error) => { - console.error(error); - process.exit(1); -}); - - ``` +To retrieve the public address of the newly created keypair, run the following command: -## Conclusion +```bash +solana address -k ./app/keypairs/deployer.json +``` -You're now fully equipped to build cross-chain contracts using the Wormhole protocol! With this tutorial, you've learned how to: +### Check the Deployer Account Balance -- Deploy sender and receiver contracts on different Testnets -- Send a cross-chain message from one blockchain to another -- Monitor the status of your cross-chain transactions using the Wormhole Explorer and Wormhole-Solidity-SDK ---- END CONTENT --- +To verify the current balance of the deployer account, run the following command: -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-token-contracts/ ---- BEGIN CONTENT --- ---- -title: Cross-Chain Token Transfers -description: Learn how to create cross-chain token transfers using Wormhole's Solidity SDK. Build and deploy smart contracts to send tokens from one blockchain to another. ---- +```bash +solana balance -k ./app/keypairs/deployer.json +``` -# Create Cross-Chain Token Transfer Contracts +!!! warning + When deploying the MultiGov Staking Program, the deployer account must have enough SOL to cover deployment costs and transaction fees. -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} + - 7.60219224 SOL for deployment costs + - 0.00542 SOL for transaction fees -## Introduction +### Fund the Deployer Account -In this tutorial, you'll learn how to create a simple cross-chain token transfer system using the Wormhole protocol via the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank}. We'll guide you through building and deploying smart contracts that enable seamless token transfers of IERC-20 tokens between blockchains. Whether you're a developer looking to explore cross-chain applications or just interested in the Wormhole protocol, this guide will help you understand the fundamentals. +If the account does not have enough SOL, use one of the following methods to add funds. -By the end of this tutorial, you'll have a working cross-chain token transfer system built with the powerful tools provided by the Wormhole Solidity SDK, which you can further customize and integrate into your projects. + - **Transfer SOL from another account** - if you already have SOL in another account, transfer it using a wallet (Phantom, Solflare, etc.) or in the terminal -## Prerequisites + ```bash + solana transfer --from /path/to/funder.json + ``` -Before you begin, ensure you have the following: + - **Request an airdrop (devnet only)** - if deploying to devnet, you can request free SOL -- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} for deploying contracts -- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\_blank} and [Celo-Alfajores](https://faucet.celo.org/alfajores){target=\_blank} to cover gas fees -- [USDC Testnet](https://faucet.circle.com/){target=\_blank} tokens on Avalanche-Fuji or/and Celo-Alfajores for cross-chain transfer -- Wallet private key + ```bash + solana airdrop 2 -k ./app/keypairs/deployer.json + ``` -## Valid Tokens for Transfer + - **Use a Solana faucet (devnet only)** - you can use online faucets to receive 10 free SOL -It's important to note that this tutorial leverages [Wormhole's TokenBridge](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/TokenBridge.sol){target=\_blank} to transfer tokens between chains. So, the tokens you'd like to transfer must have an attestation on the `TokenBridge` contract of the target blockchain. + - [Solana Faucet](https://faucet.solana.com/){target=\_blank} -To simplify this process, we've included a tool for verifying if a token has an attestation on the target chain. This tool uses the [`wrappedAsset`](https://github.com/wormhole-foundation/wormhole/blob/6130bbb6f456b42b789a71f7ea2fd049d632d2fb/ethereum/contracts/bridge/BridgeGetters.sol#L50-L52){target=\_blank} function from the `TokenBridge` contract. If the token has an attestation, the `wrappedAsset` function returns the address of the wrapped token on the target chain; otherwise, it returns the zero address. +## Deploy the MultiGov Staking Program -???- tip "Check Token Attestation" - 1. Clone the [repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank} and navigate to the project directory: - ```bash - git clone https://github.com/wormhole-foundation/demo-cross-chain-token-transfer.git - cd cross-chain-token-transfers - ``` - 2. Install the dependencies: - ```bash - npm install - ``` - - 3. Run the script to check token attestation: - ```bash - npm run verify - ``` - - 4. Follow the prompts: +With the deployer account set up and funded, you can deploy the MultiGov Staking Program to the Solana blockchain. This step involves deploying the program, verifying the deployment, and ensuring the necessary storage and metadata are correctly configured. Once the IDL is initialized, the program will be ready for further setup and interaction. - 1. Enter the RPC URL of the target chain - 2. Enter the `TokenBridge` contract address on the target chain - 3. Enter the token contract address on the source chain - 4. Enter the source chain ID +### Deploy the Program - 5. The expected output when the token has an attestation: - -
    -npm run verify - > cross-chain-token-transfer@1.0.0 verify - > npx ts-node script/check-attestation.ts - - Enter the TARGET chain RPC URL: https://alfajores-forno.celo-testnet.org - Enter the Token Bridge contract address on the TARGET chain: 0x05...E153 - Enter the token contract address on the SOURCE chain: 0x54...bc65 - Enter the SOURCE chain ID: 6 - The token is attested on the target chain. Wrapped token address: 0xDDB349c976cA2C873644F21f594767Eb5390C831 - -
    - - Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process. +Deploy the MultiGov Staking Program using Anchor: -## Project Setup +```bash +anchor deploy --provider.cluster https://api.devnet.solana.com --provider.wallet ./app/keypairs/deployer.json +``` -Let's start by initializing a new Foundry project. This will set up a basic structure for our smart contracts. +### Verify the Deployment -1. Open your terminal and run the following command to initialize a new Foundry project: - - ```bash - forge init cross-chain-token-transfers - ``` +After deployment, check if the program is successfully deployed by running the following command: - This will create a new directory named `cross-chain-token-transfers` with a basic project structure. This also initializes a new `git` repository. +```bash +solana program show INSERT_PROGRAM_ID +``` -2. Navigate into the newly created project directory: +### Extend Program Storage - ```bash - cd cross-chain-token-transfers - ``` +If the deployed program requires additional storage space for updates or functionality, extend the program storage using the following command: -3. Install the Wormhole Solidity SDK: +```bash +solana program extend INSERT_PROGRAM_ID 800000 +``` - ```bash - forge install wormhole-foundation/wormhole-solidity-sdk - ``` +### Initialize the IDL - To ease development, we'll use the Wormhole Solidity SDK, which provides useful helpers for cross-chain development. - This SDK includes the `TokenSender` and `TokenReceiver` abstract classes, which simplify sending and receiving tokens across chains. +To associate an IDL file with the deployed program, run the following command: -## Build Cross-Chain Contracts +```bash +anchor idl init --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json INSERT_PROGRAM_ID +``` -In this section, we'll build two smart contracts to send tokens from a source chain and receive them on a target chain. These contracts will interact with the Wormhole protocol to facilitate secure and seamless cross-chain token transfers. +## Configure the Staking Program -At a high level, our contracts will: +The final step after deploying the MultiGov Staking Program is configuring it for proper operation. This includes running a series of deployment scripts to initialize key components and set important governance parameters. These steps ensure that staking, governance, and cross-chain communication function as expected. -1. Send tokens from one blockchain to another using the Wormhole protocol -2. Receive and process the tokens on the target chain, ensuring they are correctly transferred to the intended recipient +### Run Deployment Scripts -Before diving into the contract implementation steps, let’s first break down the key parts of the contracts. +After deploying the program and initializing the IDL, execute the following scripts **in order** to set up the staking environment and necessary accounts. -### Sender Contract: CrossChainSender +1. Initialize the MultiGov Staking Program with default settings: -The `CrossChainSender` contract calculates the cost of sending tokens across chains and then facilitates the actual token transfer. + ```bash + npx ts-node app/deploy/01_init_staking.ts + ``` -Let's start writing the `CrossChainSender` contract: +2. Create an Account Lookup Table (ALT) to optimize transaction processing: -1. Create a new file named `CrossChainSender.sol` in the `/src` directory: - ```bash - touch src/CrossChainSender.sol + npx ts-node app/deploy/02_create_account_lookup_table.ts ``` -2. Open the file. First, we'll start with the imports and the contract setup: - - ```solidity - pragma solidity ^0.8.13; +3. Set up airlock accounts: -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; + ```bash + npx ts-node app/deploy/03_create_airlock.ts + ``` -contract CrossChainSender is TokenSender { - uint256 constant GAS_LIMIT = 250_000; +4. Deploy a metadata collector: - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - + ```bash + npx ts-node app/deploy/04_create_spoke_metadata_collector.ts ``` - This sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. - - With the contract structure in place, define the following functions within its body to enable multichain token transfers. +5. Configure vote weight window lengths: -3. Next, let's add a function that estimates the cost of sending tokens across chains: + ```bash + npx ts-node app/deploy/05_initializeVoteWeightWindowLengths.ts + ``` - ```solidity - uint16 targetChain - ) public view returns (uint256 cost) { - uint256 deliveryCost; - (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); +6. Deploy the message executor for handling governance messages: - cost = deliveryCost + wormhole.messageFee(); - } + ```bash + npx ts-node app/deploy/06_create_message_executor.ts ``` - This function, `quoteCrossChainDeposit`, helps calculate the cost of transferring tokens to a different chain. It factors in the delivery cost and the cost of publishing a message via the Wormhole protocol. - -4. Finally, we'll add the function that sends the tokens across chains: +### Set MultiGov Staking Program Key Parameters - ```solidity - uint16 targetChain, - address targetReceiver, - address recipient, - uint256 amount, - address token - ) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must equal quoteCrossChainDeposit(targetChain)" - ); +When deploying MultiGov on Solana, several key parameters need to be set. Here are the most important configuration points: - IERC20(token).transferFrom(msg.sender, address(this), amount); + - `maxCheckpointsAccountLimit` ++"u64"++ - the maximum number of checkpoints an account can have. For example, `654998` is used in production, while `15` might be used for testing + - `hubChainId` `u16` - the chain ID of the hub network where proposals are primarily managed. For example, `10002` for Sepolia testnet + - `hubProposalMetadata` ++"[u8; 20]"++ - an array of bytes representing the address of the Hub Proposal Metadata contract on Ethereum. This is used to identify proposals from the hub + - `voteWeightWindowLength` ++"u64"++ - specifies the length of the checkpoint window in seconds in which the minimum voting weight is taken. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The vote weight window helps solve problems such as manipulating votes in a chain + - `votingTokenMint` ++"Pubkey"++ - the mint address of the token used for voting + - `governanceAuthority` ++"Pubkey"++ - the account's public key with the authority to govern the staking system. The `governanceAuthority` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup + - `vestingAdmin` ++"Pubkey"++ - the account's public key for managing vesting operations. The `vestingAdmin` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup + - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke +--- END CONTENT --- - bytes memory payload = abi.encode(recipient); +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ +--- BEGIN CONTENT --- +--- +title: Upgrading MultiGov on EVM +description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. +categories: MultiGov +--- - sendTokenWithPayloadToEvm( - targetChain, - targetReceiver, - payload, - 0, - GAS_LIMIT, - token, - amount - ); - } - ``` +# Upgrade MultiGov Contracts on EVM Chains - This `sendCrossChainDeposit` function is where the actual token transfer happens. It sends the tokens to the recipient on the target chain using the Wormhole protocol. +MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. -Here’s a breakdown of what happens in each step of the `sendCrossChainDeposit` function: +## Key Considerations for Upgrades -1. **Cost calculation** - the function starts by calculating the cost of the cross-chain transfer using `quoteCrossChainDeposit`(`targetChain`). This cost includes both the delivery fee and the Wormhole message fee. The `sendCrossChainDeposit` function then checks that the user has sent the correct amount of Ether to cover this cost (`msg.value`) +- **`HubGovernor`**: + - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details -2. **Token transfer to contract** - the next step is to transfer the specified amount of tokens from the user to the contract itself using `IERC-20(token).transferFrom(msg.sender, address(this), amount)`. This ensures that the contract has custody of the tokens before initiating the cross-chain transfer +- **`HubVotePool`**: + - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` + - Requires re-registering all spokes on the new `HubVotePool` + - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` + - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` -3. **Payload encoding** - The recipient's address on the target chain is encoded into a payload using `abi.encode(recipient)`. This payload will be sent along with the token transfer, so the target contract knows who should receive the tokens on the destination chain +- **`SpokeMessageExecutor`**: + - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern + - Stores critical parameters in `SpokeMessageExecutorStorage` -4. **Cross-chain transfer** - the `sendTokenWithPayloadToEvm` function is called to initiate the cross-chain token transfer. This function: - - Specifies the `targetChain` (the Wormhole chain ID of the destination blockchain). - - Sends the `targetReceiver` contract address on the target chain that will receive the tokens. - - Attaches the payload containing the recipient's address. - - Sets the `GAS_LIMIT` for the transaction. - - Passes the token `address` and `amount` to transfer. +- **`HubEvmSpokeAggregateProposer`**: + - Needs redeployment if `HubGovernor` changes + - Requires re-registering all spokes after redeployment - This triggers the Wormhole protocol to handle the cross-chain messaging and token transfer, ensuring the tokens and payload reach the correct destination on the target chain. +- **`HubProposalMetadata`**: + - Needs redeployment if `HubGovernor` changes, as it references `HubGovernor` as a parameter -You can find the complete code for the `CrossChainSender.sol` below. +- **`SpokeMetadataCollector`**: + - Requires redeployment if the hub chain ID changes or if `HubProposalMetadata` changes -??? code "MessageSender.sol" +## Process for Major System Upgrade - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; +1. **New `HubGovernor` deployment**: + - Deploy the new `HubGovernor` contract +1. **Component redeployment**: + - Redeploy `HubEvmSpokeAggregateProposer` with the new `HubGovernor` address + - Redeploy `HubProposalMetadata` referencing the new `HubGovernor` + - If hub chain ID changes, redeploy `SpokeMetadataCollector` on all spoke chains +1. **`HubVotePool` update**: + - Set the new `HubVotePool` on the new `HubGovernor` + - Register all spokes on the new `HubVotePool` + - Register the query type and implementation for vote decoding (`HubEvmSpokeVoteDecoder`) +1. **Spoke re-registration**: + - Re-register all spokes on the new `HubEvmSpokeAggregateProposer` +1. **Verification and testing**: + - Conduct thorough testing of the new system setup + - Verify all cross-chain interactions are functioning correctly +1. **System transition and deprecation**: + - Create a proposal to switch the timelock to the new governor + - Communicate clearly to the community what changes were made +1. **Monitoring**: + - Implement a transition period where the new system is closely monitored + - Address any issues that arise promptly -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +## Important Considerations -contract CrossChainSender is TokenSender { - uint256 constant GAS_LIMIT = 250_000; +- Always prioritize system stability, upgrades should only be performed when absolutely necessary +- Thoroughly audit all new contract implementations before proposing an upgrade +- Account for all affected components across all chains in the upgrade plan +- Provide comprehensive documentation for the community about the upgrade process and any changes in functionality +- Always test upgrades extensively on testnets before implementing in production +--- END CONTENT --- - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} +Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ +--- BEGIN CONTENT --- +--- +title: Upgrading MultiGov on Solana +description: Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. +categories: MultiGov +--- - // Function to get the estimated cost for cross-chain deposit - function quoteCrossChainDeposit( - uint16 targetChain - ) public view returns (uint256 cost) { - uint256 deliveryCost; - (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice( - targetChain, - 0, - GAS_LIMIT - ); +# Upgrade MultiGov Contracts on Solana - cost = deliveryCost + wormhole.messageFee(); - } +The MultiGov Staking Program on Solana is designed to be upgradeable while maintaining stability. Upgrades introduce improvements, bug fixes, and new features but must be carefully planned and executed to prevent disruptions. - // Function to send tokens and payload across chains - function sendCrossChainDeposit( - uint16 targetChain, - address targetReceiver, - address recipient, - uint256 amount, - address token - ) public payable { - uint256 cost = quoteCrossChainDeposit(targetChain); - require( - msg.value == cost, - "msg.value must equal quoteCrossChainDeposit(targetChain)" - ); +This guide covers the key considerations and step-by-step process for upgrading the MultiGov Staking Program, including updating the program binary, Interface Description Language (IDL), and `HubProposalMetadata` while ensuring cross-chain compatibility. - IERC20(token).transferFrom(msg.sender, address(this), amount); +## Key Considerations for Upgrades - bytes memory payload = abi.encode(recipient); +- **Program upgradeability** - you can upgrade the MultiGov Staking Program on Solana using the `anchor upgrade` command + - You need the program's new bytecode (`.so` file) and an updated IDL file to reflect any changes in the program's interface to complete an upgrade + - The program's authority (deployer) must execute the upgrade - sendTokenWithPayloadToEvm( - targetChain, - targetReceiver, - payload, - 0, - GAS_LIMIT, - token, - amount - ); - } -} - ``` +- **`HubProposalMetadata`** - can be updated without redeploying the entire program. You can do this by invoking the `updateHubProposalMetadata` instruction + - You must carefully validate updates to `HubProposalMetadata` to ensure compatibility with the existing system -### Receiver Contract: CrossChainReceiver +- **Cross-chain compatibility** - ensure any changes to the Solana program do not break compatibility with the Ethereum-based `HubGovernor` + - Test upgrades thoroughly on devnet before deploying to mainnet -The `CrossChainReceiver` contract is designed to handle the receipt of tokens and payloads from another blockchain. It ensures that the tokens are correctly transferred to the designated recipient on the receiving chain. +## Upgrade the MultiGov Program -Let's start writing the `CrossChainReceiver` contract: +Follow these steps to upgrade the MultiGov Staking Program on Solana: -1. Create a new file named `CrossChainReceiver.sol` in the `/src` directory: +1. **Prepare the new program binary** - build the updated program using the provided script ```bash - touch src/CrossChainReceiver.sol + ./scripts/build_verifiable_staking_program.sh ``` -2. Open the file. First, we'll start with the imports and the contract setup: + The new program binary will be located at: - ```solidity - pragma solidity ^0.8.13; + ```bash + target/deploy/staking.so + ``` -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +2. **Upgrade the program** - use the anchor upgrade command to deploy the new program binary -contract CrossChainReceiver is TokenReceiver { - // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract + ```bash + anchor upgrade --program-id INSERT_PROGRAM_ID --provider.cluster INSERT_CLUSTER_URL INSERT_PATH_TO_PROGRAM_BINARY + ``` - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} - + Your completed anchor upgrade command should resemble the following: + ```bash + anchor upgrade --program-id DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY --provider.cluster https://api.devnet.solana.com ./target/deploy/staking.so ``` - Similar to the `CrossChainSender` contract, this sets up the basic structure of the contract, including the necessary imports and the constructor that initializes the contract with the Wormhole-related addresses. +3. **Update the IDL** - after upgrading the program, update the IDL to reflect any changes in the program's interface -3. Next, let's add a function inside the contract to handle receiving the payload and tokens: + ```bash + anchor idl upgrade INSERT_PROGRAM_ID --filepath INSERT_PATH_TO_IDL_FILE + ``` - ```solidity - bytes memory payload, - TokenReceived[] memory receivedTokens, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 // deliveryHash - ) - internal - override - onlyWormholeRelayer - isRegisteredSender(sourceChain, sourceAddress) - { - require(receivedTokens.length == 1, "Expected 1 token transfer"); + Your completed IDL upgrade command should resemble the following: + ```bash + anchor idl upgrade --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY + ``` - // Decode the recipient address from the payload - address recipient = abi.decode(payload, (address)); +4. **Update `HubProposalMetadata`** - if `HubProposalMetadata` requires an update, run the following script to invoke the `updateHubProposalMetadata` instruction and apply the changes - // Transfer the received tokens to the intended recipient - IERC20(receivedTokens[0].tokenAddress).transfer( - recipient, - receivedTokens[0].amount - ); - } + ```bash + npx ts-node app/deploy/07_update_HubProposalMetadata.ts ``` +--- END CONTENT --- - This `receivePayloadAndTokens` function processes the tokens and payload sent from another chain, decodes the recipient address, and transfers the tokens to them using the Wormhole protocol. This function also validates the emitter (`sourceAddress`) to ensure the message comes from a trusted sender. +Doc-Content: https://wormhole.com/docs/products/multigov/overview/ +--- BEGIN CONTENT --- +--- +title: MultiGov Overview +description: Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. +categories: Multigov +--- - This function ensures that: +# MultiGov Overview - - It only processes one token transfer at a time - - The `sourceAddress` is checked against a list of registered senders using the `isRegisteredSender` modifier, which verifies if the emitter is allowed to send tokens to this contract - - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface +MultiGov is a multichain governance system that enables decentralized decision-making across multiple blockchain networks. Built on Wormhole messaging, it allows DAOs to manage proposals, voting, and execution from any connected chain without relying on a single hub or bridging assets. It empowers true multichain governance by aggregating voting power across chains and coordinating secure proposal execution. -After we call `sendTokenWithPayloadToEvm` on the source chain, the message goes through the standard Wormhole message lifecycle. Once a [VAA (Verifiable Action Approval)](/docs/protocol/infrastructure/vaas/){target=\_blank} is available, the delivery provider will call `receivePayloadAndTokens` on the target chain and target address specified, with the appropriate inputs. +## Key Features -??? tip "Understanding the `TokenReceived` Struct" +MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: - Let’s delve into the fields provided to us in the `TokenReceived` struct: +- **Multichain governance** – token holders can vote and execute proposals from any supported chain +- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live +- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting +- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains +- **Flexible architecture** - can integrate with any Wormhole-supported blockchain +- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity +- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} - ```solidity - struct TokenReceived { - bytes32 tokenHomeAddress; - uint16 tokenHomeChain; - address tokenAddress; - uint256 amount; - uint256 amountNormalized; -} - ``` +## How It Works - - **`tokenHomeAddress`** - the original address of the token on its native chain. This is the same as the token field in the call to `sendTokenWithPayloadToEvm` unless the original token sent is a Wormhole-wrapped token. In that case, this will be the address of the original version of the token (on its native chain) in Wormhole address format (left-padded with 12 zeros) +1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling +2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power +3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification +4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends +5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands - - **`tokenHomeChain`** - the Wormhole chain ID corresponding to the home address above. This will typically be the source chain unless the original token sent is a Wormhole-wrapped asset, which will be the chain of the unwrapped version of the token + - - **`tokenAddress`** - the address of the IERC-20 token on the target chain that has been transferred to this contract. If `tokenHomeChain` equals the target chain, this will be the same as `tokenHomeAddress`; otherwise, it will be the Wormhole-wrapped version of the token sent +## Use Cases - - **`amount`** - the token amount sent to you with the same units as the original token. Since `TokenBridge` only sends with eight decimals of precision, if your token has 18 decimals, this will be the "amount" you sent, rounded down to the nearest multiple of 10^10 +- **Cross-Chain Treasury Management** - - **`amountNormalized`** - the amount of token divided by (1 if decimals ≤ 8, else 10^(decimals - 8)) + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets -You can find the complete code for the `CrossChainReceiver.sol` contract below: +- **Coordinated Protocol Upgrades Across Chains** -??? code "CrossChainReceiver.sol" + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + +- **Progressive Decentralization for Multichain DAOs** - ```solidity - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub -import "lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol"; -import "lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol"; +## Next Steps -contract CrossChainReceiver is TokenReceiver { - // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract +Follow these steps to get started with MultiGov: - constructor( - address _wormholeRelayer, - address _tokenBridge, - address _wormhole - ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {} +[timeline(wormhole-docs/.snippets/text/products/multigov/multigov-timeline.json)] +--- END CONTENT --- - // Function to receive the cross-chain payload and tokens with emitter validation - function receivePayloadAndTokens( - bytes memory payload, - TokenReceived[] memory receivedTokens, - bytes32 sourceAddress, - uint16 sourceChain, - bytes32 // deliveryHash - ) - internal - override - onlyWormholeRelayer - isRegisteredSender(sourceChain, sourceAddress) - { - require(receivedTokens.length == 1, "Expected 1 token transfer"); +Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ +--- BEGIN CONTENT --- +--- +title: MultiGov Guides +description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. +categories: MultiGov +--- - // Decode the recipient address from the payload - address recipient = abi.decode(payload, (address)); +# Cross-Chain treasury management proposal - // Transfer the received tokens to the intended recipient - IERC20(receivedTokens[0].tokenAddress).transfer( - recipient, - receivedTokens[0].amount - ); - } -} - ``` +This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. -## Deploy the Contracts +## Create a Proposal -Now that you've written the `CrossChainSender` and `CrossChainReceiver` contracts, it's time to deploy them to your chosen networks. +The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. -1. **Set up deployment configuration** - before deploying, you must configure the networks and the deployment environment. This information is stored in a configuration file +In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. - 1. Create a directory named deploy-config in the root of your project: +Key actions: - ```bash - mkdir deploy-config - ``` +- Define the proposal targets (two transactions to the Message Dispatcher) +- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) +- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum +- Finally, we submit the proposal to the `HubGovernor` contract - 2. Create a `config.json` file in the `deploy-config` directory: +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Prepare proposal details +address[] memory targets = new address[](2); +targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; +targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; +uint256[] memory values = new uint256[](2); +values[0] = 0; +values[1] = 0; +bytes[] memory calldatas = new bytes[](2); +// Prepare message for Optimism to mint 10 W tokens +// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) +calldatas[0] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + OPTIMISM_WORMHOLE_CHAIN_ID, + [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], + [uint256(10 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +// Prepare message for Arbitrum to receive 15 ETH +calldatas[1] = abi.encodeWithSignature( + "dispatch(bytes)", + abi.encode( + ARBITRUM_WORMHOLE_CHAIN_ID, + [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], + [uint256(15 ether)], + [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] + ) +); +string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; +// Create the proposal +uint256 proposalId = governor.propose( + targets, values, calldatas, description +) +``` - ```bash - touch deploy-config/config.json - ``` +??? interface "Parameters" - 3. Open the `config.json` file and add the following configuration: + `GOVERNOR_ADDRESS` ++"address"++ - ```json - { - "chains": [ - { - "description": "Avalanche testnet fuji", - "chainId": 6, - "rpc": "https://api.avax-test.network/ext/bc/C/rpc", - "tokenBridge": "0x61E44E506Ca5659E6c0bba9b678586fA2d729756", - "wormholeRelayer": "0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB", - "wormhole": "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C" - }, - { - "description": "Celo Testnet", - "chainId": 14, - "rpc": "https://alfajores-forno.celo-testnet.org", - "tokenBridge": "0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153", - "wormholeRelayer": "0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84", - "wormhole": "0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56" - } - ] -} - ``` + The address of the `HubGovernor` contract on Ethereum Mainnet. - This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the Wormhole relayer, and the Wormhole Core Contract. + --- - For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=_blank}. + `targets` ++"address[]"++ - !!! note - You can add your desired chains to this file by specifying the required fields for each chain. In this example, we use the Avalanche Fuji and Celo Alfajores Testnets. + An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. - 4. Create a `contracts.json` file in the `deploy-config` directory: + --- - ```bash - echo '{}' > deploy-config/contracts.json - ``` + `values` ++"uint256[]"++ - This file can be left blank initially. It will be automatically updated with the deployed contract addresses after a successful deployment + An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. -2. **Set up your Node.js environment** - you'll need to set up your Node.js environment to run the deployment script + --- - 1. Initialize a Node.js project: + `calldatas` ++"bytes[]"++ - ```bash - npm init -y - ``` + The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. - 2. Create a `.gitignore` file to ensure your private key isn't accidentally exposed or committed to version control: + --- - ```bash - echo ".env" >> .gitignore - ``` - - 3. Install the necessary dependencies: + `description` ++"string"++ - ```bash - npm install ethers dotenv readline-sync @types/readline-sync - ``` + A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. - These dependencies are required for the deployment script to work properly. +??? interface "Returns" -3. **Compile your smart contracts** - compile your smart contracts using Foundry. This ensures that your contracts are up-to-date and ready for deployment + `proposalId` ++"uint256"++ - - Run the following command to compile your contracts: + The ID of the newly created proposal on the hub chain. - ```bash - forge build - ``` +## Vote on the Proposal via Spoke - This will generate the necessary ABI and bytecode files in a directory named `/out`. +Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. - The expected output should be similar to this: +Key actions: -
    -forge build - > [⠒] Compiling... - > [⠰] Compiling 30 files with 0.8.23 - [⠔] Solc 0.8.23 finished in 2.29s -Compiler run successful! - -
    +- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain +- Cast a vote in support of the proposal -4. **Write the deployment script** - you’ll need a script to automate the deployment of your contracts. Let’s create the deployment script +```solidity +// Connect to the SpokeVoteAggregator contract of the desired chain +SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); +// Cast a vote +uint8 support = 1; // 1 for supporting, 0 for opposing +uint256 weight = voteAggregator.castVote(proposalId, support); +``` - 1. Create a new file named `deploy.ts` in the `/script` directory: +??? interface "Parameters" - ```bash - touch script/deploy.ts - ``` + `VOTE_AGGREGATOR_ADDRESS` ++"address"++ - 2. Open the file and load imports and configuration: + The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). - ```typescript - import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; + --- -dotenv.config(); - ``` + `proposalId` ++"uint256"++ - Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal. + The ID of the proposal created on the hub chain, which is being voted on. - 3. Define interfaces to use for chain configuration and contract deployment: + --- - ```typescript - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} + `support` ++"uint8"++ -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} - ``` + The vote being cast (`1` for supporting the proposal, `0` for opposing). - These interfaces define the structure of the chain configuration and the contract deployment details. +??? interface "Returns" - 4. Load and select the chains for deployment: + `weight` ++"uint256"++ - ```typescript - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} + The weight of the vote, determined by the voter’s token holdings on the spoke chain. -function selectChain( - chains: ChainConfig[], - role: 'source' | 'target' -): ChainConfig { - console.log(`\nSelect the ${role.toUpperCase()} chain:`); - chains.forEach((chain, index) => { - console.log(`${index + 1}: ${chain.description}`); - }); +## Vote Aggregation - const chainIndex = - readlineSync.questionInt( - `\nEnter the number for the ${role.toUpperCase()} chain: ` - ) - 1; - return chains[chainIndex]; -} - ``` +In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. - The `loadConfig` function reads the chain configuration from the `config.json` file, and the `selectChain` function allows the user to choose the source and target chains for deployment interactively. The user is prompted in the terminal to select which chains to use, making the process interactive and user-friendly. +Key actions: - 5. Define the main function for deployment and load the chain configuration: +- Aggregate votes from different chains and submit them to the hub chain for tallying - ```typescript - const chains = loadConfig(); +```solidity +// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) +hubVotePool.crossChainVote(queryResponseRaw, signatures); +``` - const sourceChain = selectChain(chains, 'source'); - const targetChain = selectChain(chains, 'target'); - ``` +??? interface "Parameters" - - The `main` function is the entry point for the deployment script - - We then call the `loadConfig` function we previously defined to load the chain configuration from the `config.json` file + `queryResponseRaw` ++"bytes"++ - 6. Set up provider and wallet: - - ```typescript - const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); - ``` - - The scripts establish a connection to the blockchain using a provider and create a wallet instance using a private key. This wallet is responsible for signing the deployment transaction on the source chain. + The raw vote data from the spoke chains. - 7. Read the compiled contracts: + --- - ```typescript - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); - ``` + `signatures` ++"bytes"++ - - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract - - The file is in the `../out/` directory, which contains the ABI (Application Binary Interface) and bytecode generated during contract compilation - - It uses the `fs.readFileSync` function to read the file and `JSON.parse` to convert the file contents (in JSON format) into a JavaScript object + Cryptographic signatures that verify the validity of the votes from the spoke chains. - 8. Extract the contract ABI and bytecode: +## Execute Proposal and Dispatch Cross-Chain Messages - ```typescript - const bytecode = senderJson.bytecode; - ``` +After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. - - **ABI (Application Binary Interface)** - defines the structure of the contract’s functions, events, and data types, allowing the front end to interact with the contract on the blockchain - - **Bytecode** - this is the compiled machine code that will be deployed to the blockchain to create the contract +Key actions: - 9. Create the Contract Factory: +- Execute the proposal after the voting period ends and the proposal passes +- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. - ```typescript - abi, - bytecode, - wallet - ); - ``` +```solidity +HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); +// Standard timelock execution +governor.execute(targets, values, calldatas, descriptionHash); +``` - - **`ethers.ContractFactory`** - creates a new contract factory using the ABI, bytecode, and a wallet (representing the signer). The contract factory is responsible for deploying instances of the contract to the blockchain - - This is a crucial step for deploying the contract since the factory will create and deploy the `CrossChainSender` contract +??? interface "Parameters" - 10. Deploy the `CrossChainSender` and `CrossChainReceiver` contracts: + `governor` ++"HubGovernor"++ - === "`CrossChainSender`" - ```typescript - const senderContract = await CrossChainSenderFactory.deploy( - sourceChain.wormholeRelayer, - sourceChain.tokenBridge, - sourceChain.wormhole - ); - await senderContract.waitForDeployment(); - ``` + The `HubGovernor` contract instance. - === "`CrossChainReceiver`" - ```typescript - process.env.PRIVATE_KEY!, - targetProvider - ); - const receiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainReceiver.sol/CrossChainReceiver.json' - ), - 'utf8' - ) - ); - const CrossChainReceiverFactory = new ethers.ContractFactory( - receiverJson.abi, - receiverJson.bytecode, - targetWallet - ); + --- - const receiverContract = await CrossChainReceiverFactory.deploy( - targetChain.wormholeRelayer, - targetChain.tokenBridge, - targetChain.wormhole - ); - await receiverContract.waitForDeployment(); - ``` + `targets` ++"address[]"++ - Both functions deploy the respective contracts to the selected chains. + An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). - For the `CrossChainReceiver` contract: + --- - - It defines the wallet related to the target chain - - The logic reads the compiled ABI and bytecode from the JSON file generated during compilation - - It creates a new contract factory using the ABI, bytecode, and wallet - - It deploys the contract to the selected chain passing in the Wormhole Relayer, `TokenBridge`, and Wormhole addresses + `values` ++"uint256[]"++ - 11. Save the deployed contract addresses: + An array of values (in Wei) associated with each transaction (both are zero in this case). - === "`senderAddress`" - ```typescript - console.log( - `CrossChainSender on ${sourceChain.description}: ${senderAddress}` - ); - ``` + --- - === "`receiverAddress`" - ```typescript - console.log( - `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` - ); - ``` + `calldatas` ++"bytes[]"++ - You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference. + The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). - 12. Register the `CrossChainSender` address on the target chain: + --- - ```typescript - receiverAddress, - receiverJson.abi, - targetWallet - ); + `descriptionHash` ++"bytes32"++ - const tx = await CrossChainReceiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) - ); + A hash of the proposal’s description, used to verify the proposal before execution. - await tx.wait(); - ``` +??? interface "Returns" - After you deploy the `CrossChainReceiver` contract on the target network, the sender contract address from the source chain needs to be registered. This ensures that only messages from the registered `CrossChainSender` contract are processed. + No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. - This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `CrossChainReceiver` contract. +Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. +--- END CONTENT --- - 13. Save the deployment details: +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Architecture +description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. +categories: NTT, Transfer +--- - ???- example "Save Deployment Details Example" - ```typescript - __dirname, - '../deploy-config/contracts.json' - ); - let deployedContracts: DeployedContracts = {}; +## Introduction - if (fs.existsSync(deployedContractsPath)) { - deployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); - } +The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. - // Update the contracts.json file: - // If a contract already exists on a chain, update its address; otherwise, add a new entry. - if (!deployedContracts[sourceChain.chainId]) { - deployedContracts[sourceChain.chainId] = { - networkName: sourceChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[sourceChain.chainId].CrossChainSender = - senderAddress.toString(); - deployedContracts[sourceChain.chainId].deployedAt = - new Date().toISOString(); - if (!deployedContracts[targetChain.chainId]) { - deployedContracts[targetChain.chainId] = { - networkName: targetChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[targetChain.chainId].CrossChainReceiver = - receiverAddress.toString(); - deployedContracts[targetChain.chainId].deployedAt = - new Date().toISOString(); +## System Components - // Save the updated contracts.json file - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); - ``` - - Add your desired logic to save the deployed contract addresses in a JSON file (or another format). This will be important later when transferring tokens, as you'll need these addresses to interact with the deployed contracts. +The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. - 14. Handle errors and finalize the script: +### Managers - ```typescript - if (error.code === 'INSUFFICIENT_FUNDS') { - console.error( - 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' - ); - } else { - console.error('An unexpected error occurred:', error.message); - } - process.exit(1); - } -} +_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. -main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` +Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. - The try-catch block wraps the deployment logic to catch any errors that may occur. +A manager is responsible for: - - If the error is due to insufficient funds, it logs a clear message about needing more gas fees - - For any other errors, it logs the specific error message to help with debugging +- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer +- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers + - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted + - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded - The `process.exit(1)` ensures that the script exits with a failure status code if any error occurs. + Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit - You can find the full code for the `deploy.ts` file below: +- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed +- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility - ??? code "deploy.ts" +### Transceivers - ```solidity - import { BytesLike, ethers } from 'ethers'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. -dotenv.config(); +While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +Transceivers are entrusted with several responsibilities: -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} +- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing +- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer +- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed -function loadConfig(): ChainConfig[] { - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +How it works: -function selectChain( - chains: ChainConfig[], - role: 'source' | 'target' -): ChainConfig { - console.log(`\nSelect the ${role.toUpperCase()} chain:`); - chains.forEach((chain, index) => { - console.log(`${index + 1}: ${chain.description}`); - }); +1. The transceiver receives instructions from the manager to send messages across chains +2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred +3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain - const chainIndex = - readlineSync.questionInt( - `\nEnter the number for the ${role.toUpperCase()} chain: ` - ) - 1; - return chains[chainIndex]; -} +![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) -async function main() { - const chains = loadConfig(); +!!! note + [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. - const sourceChain = selectChain(chains, 'source'); - const targetChain = selectChain(chains, 'target'); +#### Custom Transceivers - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); +The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. - const senderJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. - const abi = senderJson.abi; - const bytecode = senderJson.bytecode; +![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) - const CrossChainSenderFactory = new ethers.ContractFactory( - abi, - bytecode, - wallet - ); +The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. - try { - const senderContract = await CrossChainSenderFactory.deploy( - sourceChain.wormholeRelayer, - sourceChain.tokenBridge, - sourceChain.wormhole - ); - await senderContract.waitForDeployment(); +For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. - // Safely access the deployed contract's address - const senderAddress = (senderContract as ethers.Contract).target; - console.log( - `CrossChainSender on ${sourceChain.description}: ${senderAddress}` - ); +## Lifecycle of a Message - const targetWallet = new ethers.Wallet( - process.env.PRIVATE_KEY!, - targetProvider - ); - const receiverJson = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainReceiver.sol/CrossChainReceiver.json' - ), - 'utf8' - ) - ); - const CrossChainReceiverFactory = new ethers.ContractFactory( - receiverJson.abi, - receiverJson.bytecode, - targetWallet - ); +The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. - const receiverContract = await CrossChainReceiverFactory.deploy( - targetChain.wormholeRelayer, - targetChain.tokenBridge, - targetChain.wormhole - ); - await receiverContract.waitForDeployment(); +### Transfer - // Safely access the deployed contract's address - const receiverAddress = (receiverContract as ethers.Contract).target; - console.log( - `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}` - ); +The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. - // Register the sender contract in the receiver contract - console.log( - `Registering CrossChainSender (${senderAddress}) as a valid sender in CrossChainReceiver (${receiverAddress})...` - ); +In both cases: - const CrossChainReceiverContract = new ethers.Contract( - receiverAddress, - receiverJson.abi, - targetWallet - ); +- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain +- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain - const tx = await CrossChainReceiverContract.setRegisteredSender( - sourceChain.chainId, - ethers.zeroPadValue(senderAddress as BytesLike, 32) - ); +Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. - await tx.wait(); - console.log( - `CrossChainSender registered as a valid sender on ${targetChain.description}` - ); +### Rate Limit - // Load existing deployed contract addresses from contracts.json - const deployedContractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - let deployedContracts: DeployedContracts = {}; +Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. - if (fs.existsSync(deployedContractsPath)) { - deployedContracts = JSON.parse( - fs.readFileSync(deployedContractsPath, 'utf8') - ); - } +- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error +- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error - // Update the contracts.json file: - // If a contract already exists on a chain, update its address; otherwise, add a new entry. - if (!deployedContracts[sourceChain.chainId]) { - deployedContracts[sourceChain.chainId] = { - networkName: sourceChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[sourceChain.chainId].CrossChainSender = - senderAddress.toString(); - deployedContracts[sourceChain.chainId].deployedAt = - new Date().toISOString(); +Both chains emit events or logs when transfers are rate-limited or queued. - if (!deployedContracts[targetChain.chainId]) { - deployedContracts[targetChain.chainId] = { - networkName: targetChain.description, - deployedAt: new Date().toISOString(), - }; - } - deployedContracts[targetChain.chainId].CrossChainReceiver = - receiverAddress.toString(); - deployedContracts[targetChain.chainId].deployedAt = - new Date().toISOString(); +### Send - // Save the updated contracts.json file - fs.writeFileSync( - deployedContractsPath, - JSON.stringify(deployedContracts, null, 2) - ); - } catch (error: any) { - if (error.code === 'INSUFFICIENT_FUNDS') { - console.error( - 'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.' - ); - } else { - console.error('An unexpected error occurred:', error.message); - } - process.exit(1); - } -} +After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. -main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` +- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message +- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification -5. **Add your private key** - you'll need to provide your private key. It allows your deployment script to sign the transactions that deploy the smart contracts to the blockchain. Without it, the script won't be able to interact with the blockchain on your behalf +In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. - Create a `.env` file in the root of the project and add your private key: +### Receive - ```bash - touch .env - ``` +Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. - Inside `.env`, add your private key in the following format: +- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers +- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing - ```env - PRIVATE_KEY=INSERT_PRIVATE_KEY - ``` - -6. **Run the deployment script** +In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. - 1. Open a terminal and run the following command: +### Mint or Unlock - ```bash - npx ts-node script/deploy.ts - ``` +Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. - This will execute the deployment script, deploying both contracts to the selected chains. +- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred +- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced - 2. Check the deployment output: +In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. +--- END CONTENT --- - - You will see the deployed contract addresses printed in the terminal if successful. The `contracts.json` file will be updated with these addresses - - If you encounter an error, the script will provide feedback, such as insufficient funds for gas +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/security/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Security +description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. +categories: NTT, Transfer +--- -If you followed the logic provided in the full code above, your terminal output should look something like this: +# Security -
    -npx ts-node deploy.ts - > cross-chain-token-transfer@1.0.0 deploy - > npx ts-node script/deploy.ts - Select the SOURCE chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the SOURCE chain: 1 - - Select the TARGET chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the TARGET chain: 2 - CrossChainSender Avalanche testnet fuji: 0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3 - CrossChainReceiver Celo Testnet: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1 - - Registering CrossChainSender (0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3) as a valid sender in CrossChainReceiver (0xD720BFF42a0960cfF1118454A907a44dB358f2b1)... - - CrossChainSender registered as a valid sender on Celo Testnet - -
    +## Global Accountant +The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. -## Transfer Tokens Across Chains +This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. -### Quick Recap +[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. -Up to this point, you've set up a new Solidity project using Foundry, developed two key contracts (`CrossChainSender` and `CrossChainReceiver`), and created a deployment script to deploy these contracts to different blockchain networks. The deployment script also saves the new contract addresses for easy reference. With everything in place, it's time to transfer tokens using the deployed contracts. +## Governance and Upgradeability -In this step, you'll write a script to transfer tokens across chains using the `CrossChainSender` and `CrossChainReceiver` contracts you deployed earlier. This script will interact with the contracts and facilitate the cross-chain token transfer. +Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. -### Transfer Script +The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: -1. **Set up the transfer script** +- Adding or removing a transceiver address from the registry +- Setting the token contract address on a bridging contract +- Setting the Wormhole Core Contract address on a bridging contract +- Setting the registered bridging contract address on the token contract - 1. Create a new file named `transfer.ts` in the `/script` directory: +This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +--- END CONTENT --- - ```bash - touch script/transfer.ts - ``` +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Access Control +description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. +categories: NTT, Transfer +--- - 2. Open the file. Start with the necessary imports, interfaces and configurations: +## Owner and Pauser Roles - ```typescript - import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). -dotenv.config(); +NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused +- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; +You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. + +```json +{ + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": true, // set to true to pause the contract + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + //... + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } } - ``` +``` - These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input. +!!! note + While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. - 3. Load configuration and contracts: +The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. +Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. +--- END CONTENT --- - ```typescript - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Rate Limiting +description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. +categories: NTT, Transfer +--- -function loadDeployedContracts(): DeployedContracts { - const contractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - if ( - !fs.existsSync(contractsPath) || - fs.readFileSync(contractsPath, 'utf8').trim() === '' - ) { - console.error( - 'No contracts found. Please deploy contracts first before transferring tokens.' - ); - process.exit(1); - } - return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); -} - ``` +## Introduction - These functions load the network and contract details that were saved during deployment. +The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. - 4. Allow users to select source and target chains: +If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. - Refer to the deployed contracts and create logic as desired. In our example, we made this process interactive, allowing users to select the source and target chains from all the historically deployed contracts. This interactive approach helps ensure the correct chains are selected for the token transfer. +You can configure the following limits on every chain where NTT is deployed directly using the manager: - ```typescript - chainId: number; - networkName: string; -} { - const sourceOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainSender - ); +- **Sending limit** - a single outbound limit for sending tokens from the chain +- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum - if (sourceOptions.length === 0) { - console.error('No source chains available with CrossChainSender deployed.'); - process.exit(1); - } +Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. - console.log('\nSelect the source chain:'); - sourceOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +## Update Rate Limits - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; - return { - chainId: Number(sourceOptions[selectedIndex][0]), - networkName: sourceOptions[selectedIndex][1].networkName, - }; -} +To configure or update the sending and receiving rate limits, follow these steps: -function selectTargetChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const targetOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainReceiver - ); +1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts - if (targetOptions.length === 0) { - console.error( - 'No target chains available with CrossChainReceiver deployed.' - ); - process.exit(1); - } +2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed - console.log('\nSelect the target chain:'); - targetOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); + ```json + "limits": { + "outbound": "1000.000000000000000000", + "inbound": { + "Ethereum": "100.000000000000000000", + "Arbitrum": "50.000000000000000000" + } + } + ``` - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; - return { - chainId: Number(targetOptions[selectedIndex][0]), - networkName: targetOptions[selectedIndex][1].networkName, - }; -} - ``` + - **`outbound`** - sets the maximum tokens allowed to leave the chain + - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains -2. **Implement the token transfer logic** +3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain - 1. Start the `main` function: - - ```typescript - const chains = loadConfig(); - const deployedContracts = loadDeployedContracts(); + ```bash + ntt push + ``` - // Select the source chain (only show chains with CrossChainSender deployed) - const { chainId: sourceChainId, networkName: sourceNetworkName } = - selectSourceChain(deployedContracts); - const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; +4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status - // Select the target chain (only show chains with CrossChainReceiver deployed) - const { chainId: targetChainId, networkName: targetNetworkName } = - selectTargetChain(deployedContracts); - const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; + ```bash + ntt status + ``` - // Set up providers and wallets - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); +???- note "`deployment.json` example" + ```json + { + "network": "Testnet", + "chains": { + "Sepolia": { + "version": "1.1.0", + "mode": "burning", + "paused": false, + "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", + "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", + "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", + "transceivers": { + "threshold": 1, + "wormhole": { + "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + }, + "limits": { + "outbound": "184467440737.095516150000000000", + "inbound": { + "ArbitrumSepolia": "500.000000000000000000" + } + }, + "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" + } + } + } + ``` - // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) - const CrossChainSenderArtifact = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +## Queuing Mechanism - const abi = CrossChainSenderArtifact.abi; +When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: - // Create the contract instance using the full ABI - const CrossChainSender = new ethers.Contract( - deployedContracts[sourceChainId].CrossChainSender!, - abi, - wallet - ); - ``` - - The `main` function is where the token transfer logic will reside. It loads the chain and contract details, sets up the wallet and provider, and loads the `CrossChainSender` contract. +- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer +- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain - 2. Ask the user for token transfer details: +Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. - You'll now ask the user for the token contract address, the recipient address on the target chain, and the amount of tokens to transfer. +## Cancel Flows - ```typescript - 'Enter the token contract address: ' - ); - const recipientAddress = readlineSync.question( - 'Enter the recipient address on the target chain: ' - ); +If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. +--- END CONTENT --- - // Get the token contract - const tokenContractDecimals = new ethers.Contract( - tokenAddress, - [ - 'function decimals() view returns (uint8)', - 'function approve(address spender, uint256 amount) public returns (bool)', - ], - wallet - ); +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers FAQs +description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +categories: NTT, Transfer +--- - // Fetch the token decimals - const decimals = await tokenContractDecimals.decimals(); +# Wormhole NTT FAQs - // Get the amount from the user, then parse it according to the token's decimals - const amount = ethers.parseUnits( - readlineSync.question('Enter the amount of tokens to transfer: '), - decimals - ); - ``` +## Do you have an example of how cross-chain lending can be implemented using Wormhole? - This section of the script prompts the user for the token contract address and the recipient's address, fetches the token's decimal value, and parses the amount accordingly. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. - 3. Initiate the transfer: +Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. - Finally, initiate the cross-chain transfer and log the details. +## What causes the "No protocols registered for Evm" error in Wormhole SDK? - ```typescript - // Approve the CrossChainSender contract to transfer tokens on behalf of the user - const tokenContract = new ethers.Contract( - tokenAddress, - ['function approve(address spender, uint256 amount) public returns (bool)'], - wallet - ); +This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. - const approveTx = await tokenContract.approve( - deployedContracts[sourceChainId].CrossChainSender!, - amount - ); - await approveTx.wait(); - console.log(`Approved tokens for cross-chain transfer.`); +To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: - // Initiate the cross-chain transfer - const transferTx = await CrossChainSender.sendCrossChainDeposit( - targetChainId, - deployedContracts[targetChainId].CrossChainReceiver!, - recipientAddress, - amount, - tokenAddress, - { value: cost } // Attach the necessary fee for cross-chain transfer - ); - await transferTx.wait(); - console.log( - `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` - ); -} - ``` +```rust +import '@wormhole-foundation/sdk-evm-ntt'; +``` - This part of the script first approves the token transfer, then initiates the cross-chain transfer using the `CrossChainSender` contract, and finally logs the transaction hash for the user to track. +By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. - 4. Finalize the script: +## How can I transfer ownership of NTT to a multisig? - ```typescript - console.error(error); - process.exit(1); -}); - ``` +Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. - This section finalizes the script by calling the `main` function and handling any errors that may occur during the token transfer process. +1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) +2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer +3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) -You can find the full code for the `transfer.ts` file below: +For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. -??? code "transfer.ts" +## How can I specify a custom RPC for NTT? - ```solidity - import { ethers } from 'ethers'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as dotenv from 'dotenv'; -import readlineSync from 'readline-sync'; +To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. -dotenv.config(); +Below’s an example of how the `overrides.json` file should be structured: -interface ChainConfig { - description: string; - chainId: number; - rpc: string; - tokenBridge: string; - wormholeRelayer: string; - wormhole: string; -} +???- code "`overrides.json`" + ```json + { + "chains": { + "Bsc": { + "rpc": "http://127.0.0.1:8545" + }, + "Sepolia": { + "rpc": "http://127.0.0.1:8546" + }, + "Solana": { + "rpc": "http://127.0.0.1:8899" + } + } + } + ``` -interface DeployedContracts { - [chainId: number]: { - networkName: string; - CrossChainSender?: string; - CrossChainReceiver?: string; - deployedAt: string; - }; -} +## How can I redeem tokens if NTT rate limits block them on the target chain? -function loadConfig(): ChainConfig[] { - const configPath = path.resolve(__dirname, '../deploy-config/config.json'); - return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains; -} +If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. -function loadDeployedContracts(): DeployedContracts { - const contractsPath = path.resolve( - __dirname, - '../deploy-config/contracts.json' - ); - if ( - !fs.existsSync(contractsPath) || - fs.readFileSync(contractsPath, 'utf8').trim() === '' - ) { - console.error( - 'No contracts found. Please deploy contracts first before transferring tokens.' - ); - process.exit(1); - } - return JSON.parse(fs.readFileSync(contractsPath, 'utf8')); -} +To resolve this: -function selectSourceChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const sourceOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainSender - ); +1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed +2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain - if (sourceOptions.length === 0) { - console.error('No source chains available with CrossChainSender deployed.'); - process.exit(1); - } +In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. - console.log('\nSelect the source chain:'); - sourceOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +## What are the challenges of deploying NTT to non-EVM chains? - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the source chain: `) - 1; - return { - chainId: Number(sourceOptions[selectedIndex][0]), - networkName: sourceOptions[selectedIndex][1].networkName, - }; -} +NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. -function selectTargetChain(deployedContracts: DeployedContracts): { - chainId: number; - networkName: string; -} { - const targetOptions = Object.entries(deployedContracts).filter( - ([, contracts]) => contracts.CrossChainReceiver - ); +## Does the NTT manager function as an escrow account for a hub chain? - if (targetOptions.length === 0) { - console.error( - 'No target chains available with CrossChainReceiver deployed.' - ); - process.exit(1); - } +Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. - console.log('\nSelect the target chain:'); - targetOptions.forEach(([chainId, contracts], index) => { - console.log(`${index + 1}: ${contracts.networkName}`); - }); +## Which functions or events does Connect rely on for NTT integration? - const selectedIndex = - readlineSync.questionInt(`\nEnter the number for the target chain: `) - 1; - return { - chainId: Number(targetOptions[selectedIndex][0]), - networkName: targetOptions[selectedIndex][1].networkName, - }; -} +Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: -async function main() { - const chains = loadConfig(); - const deployedContracts = loadDeployedContracts(); +- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain +- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion - // Select the source chain (only show chains with CrossChainSender deployed) - const { chainId: sourceChainId, networkName: sourceNetworkName } = - selectSourceChain(deployedContracts); - const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!; +These functions ensure Connect can handle token transfers and manage chain-rate limits. - // Select the target chain (only show chains with CrossChainReceiver deployed) - const { chainId: targetChainId, networkName: targetNetworkName } = - selectTargetChain(deployedContracts); - const targetChain = chains.find((chain) => chain.chainId === targetChainId)!; +## How does the relayer contract determine which transceiver to call? - // Set up providers and wallets - const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc); - const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider); +The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. - // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat) - const CrossChainSenderArtifact = JSON.parse( - fs.readFileSync( - path.resolve( - __dirname, - '../out/CrossChainSender.sol/CrossChainSender.json' - ), - 'utf8' - ) - ); +## How do I create a verifier or transceiver? - const abi = CrossChainSenderArtifact.abi; +To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. - // Create the contract instance using the full ABI - const CrossChainSender = new ethers.Contract( - deployedContracts[sourceChainId].CrossChainSender!, - abi, - wallet - ); +For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. - // Display the selected chains - console.log( - `\nInitiating transfer from ${sourceNetworkName} to ${targetNetworkName}.` - ); +## Can I use Hetzner for the NTT deployment? - // Ask the user for token transfer details - const tokenAddress = readlineSync.question( - 'Enter the token contract address: ' - ); - const recipientAddress = readlineSync.question( - 'Enter the recipient address on the target chain: ' - ); +No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. - // Get the token contract - const tokenContractDecimals = new ethers.Contract( - tokenAddress, - [ - 'function decimals() view returns (uint8)', - 'function approve(address spender, uint256 amount) public returns (bool)', - ], - wallet - ); +## How can I transfer tokens with NTT with an additional payload? - // Fetch the token decimals - const decimals = await tokenContractDecimals.decimals(); +You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. - // Get the amount from the user, then parse it according to the token's decimals - const amount = ethers.parseUnits( - readlineSync.question('Enter the amount of tokens to transfer: '), - decimals - ); +- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message +- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message - // Calculate the cross-chain transfer cost - const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId); +!!!Important + You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. - // Approve the CrossChainSender contract to transfer tokens on behalf of the user - const tokenContract = new ethers.Contract( - tokenAddress, - ['function approve(address spender, uint256 amount) public returns (bool)'], - wallet - ); +## Why use NTT over xERC20? - const approveTx = await tokenContract.approve( - deployedContracts[sourceChainId].CrossChainSender!, - amount - ); - await approveTx.wait(); - console.log(`Approved tokens for cross-chain transfer.`); - - // Initiate the cross-chain transfer - const transferTx = await CrossChainSender.sendCrossChainDeposit( - targetChainId, - deployedContracts[targetChainId].CrossChainReceiver!, - recipientAddress, - amount, - tokenAddress, - { value: cost } // Attach the necessary fee for cross-chain transfer - ); - await transferTx.wait(); - console.log( - `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}` - ); -} - -main().catch((error) => { - console.error(error); - process.exit(1); -}); - ``` +Shortcomings of xERC20: -### Transfer Tokens +- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach +- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies +- **No access control** - there are no built-in access controls for managing token transfers securely +- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security +- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups -Now that your transfer script is ready, it’s time to execute it and perform a cross-chain token transfer. +While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. -1. **Run the transfer script** +## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? - Open your terminal and run the transfer script: +To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. - ```bash - npx ts-node script/transfer.ts - ``` +## Is there a way to use NTT tokens with chains that don't currently support NTT? - This command will start the script, prompting you to select the source and target chains, input the token address, recipient address, and the amount of tokens to transfer. +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: -2. **Follow the prompts** - the script will guide you through selecting the source and target chains and entering the necessary details for the token transfer. Once you provide all the required information, the script will initiate the token transfer +- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) +- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism +- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT -3. **Verify the transaction** - after running the script, you should see a confirmation message with the transaction hash. You can use this transaction hash to check the transfer status on the respective blockchain explorers +This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. -You can verify the transaction on the [Wormhole Explorer](https://wormholescan.io/){target=\_balnk} using the link provided in the terminal output. This explorer also offers the option to add the transferred token to your MetaMask wallet automatically. +## How can I update my NTT CLI version? -If you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this: +To update an existing NTT CLI installation, run the following command in your terminal: -
    -npx ts-node transfer.ts - > cross-chain-token-transfer@1.0.0 transfer - > npx ts-node script/transfer.ts - - Select the source chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the SOURCE chain: 1 - - Select the target chain: - 1: Avalanche testnet fuji - 2: Celo Testnet - - Enter the number for the TARGET chain: 2 - - Initiating transfer from Avalanche testnet fuji to Celo Testnet - Enter the token contract address: 0x5425890298aed601595a70ab815c96711a31bc65 - Enter the recipient address on the target chain: INSERT_YOUR_WALLET_ADDRESS - Enter the amount of tokens to transfer: 2 - Approved tokens for cross-chain transfer. - Transfer initiated from Avalanche testnet fuji to Celo Testnet. Transaction Hash: 0x4a923975d955c1f226a1c2f61a1a0fa1ab1a9e229dc29ceaeadf8ef40acd071f - -
    +```bash +ntt update +``` -!!! note - In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Celo Alfajores Testnet. We sent two units of USDC Testnet tokens using the token contract address `0x5425890298aed601595a70ab815c96711a31bc65`. You can replace these details with those relevant to your project or use the same for testing purposes. +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. -## Resources +For local development, you can update your CLI version from a specific branch or install from a local path. -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in the [Cross-Chain Token Transfers GitHub repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\_blank}. The repository includes all the scripts, contracts, and configurations needed to deploy and transfer tokens across chains using the Wormhole protocol. +To install from a specific branch, run: -## Conclusion +```bash +ntt update --branch foo +``` -Congratulations! You've successfully built and deployed a cross-chain token transfer system using Solidity and the Wormhole protocol. You've learned how to: +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` - - Set up a new Solidity project using Foundry - - Develop smart contracts to send and receive tokens across chains - - Write deployment scripts to manage and deploy contracts on different networks +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/replace-signatures/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ --- BEGIN CONTENT --- --- -title: Replace Outdated Signatures in VAAs -description: Learn how to fetch, validate, and replace outdated signatures in Wormhole VAAs using Wormholescan and the Wormhole SDK to ensure seamless processing. +title: Get Started with NTT +description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. +categories: NTT, Transfer --- -# Replace Outdated Signatures in VAAs - -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank} +# Get Started with NTT ## Introduction -Cross-chain transactions in Wormhole rely on [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, which contain signatures from a trusted set of validators called [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}. These signatures prove that the network approved an action, such as a token transfer. - -However, the set of Guardians changes over time. If a user generates a transaction and waits too long before redeeming it, the Guardian set may have already changed. This means the VAA will contain outdated signatures from Guardians, who are no longer part of the network, causing the transaction to fail. +The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. -Instead of discarding these VAAs, we can fetch updated signatures and replace the outdated ones to ensure smooth processing. +If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. -In this tutorial, you'll build a script from scratch to: +## Prerequisites -- Fetch a VAA from [Wormholescan](https://wormholescan.io/#/developers/api-doc){target=\_blank} -- Validate its signatures against the latest Guardian set -- Replace outdated signatures using the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} -- Output a valid VAA ready for submission +Before you begin, make sure you have: -By the end, you'll have a script that ensures VAAs remain valid and processable, avoiding transaction failures. +- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} +- [Bun installed](https://bun.sh/){target=\_blank} +- A wallet private key with tokens on supported chains +- ERC-20 or SPL tokens already deployed on the source and destination chains -## Prerequisites +## Don’t Have a Token Yet? -Before you begin, ensure you have the following: +To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally +???- interface "Deploy an ERC-20 Token on EVM" + Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. -## Project Setup + 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} -In this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript. + 2. **Clone the repository** – fetch the example contract repository -1. **Create the project** - set up the directory and navigate into it + ```bash + git clone https://github.com/wormhole-foundation/example-ntt-token.git + cd example-ntt-token + ``` + + 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses - ```bash - mkdir wormhole-scan-api-demo - cd wormhole-scan-api-demo - ``` + ```bash + forge create --broadcast \ + --rpc-url INSERT_RPC_URL \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + src/PeerToken.sol:PeerToken \ + --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS + ``` -2. **Initialize a Node.js project** - generate a `package.json` file + 4. **Mint tokens** – send tokens to your address - ```bash - npm init -y - ``` + ```bash + cast send INSERT_TOKEN_ADDRESS \ + "mint(address,uint256)" \ + INSERT_RECIPIENT_ADDRESS \ + INSERT_AMOUNT_IN_WEI \ + --private-key INSERT_YOUR_PRIVATE_KEY \ + --rpc-url INSERT_RPC_URL + ``` -3. **Set up TypeScript** - create a `tsconfig.json` file + !!! note + This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). - ```bash - touch tsconfig.json - ``` - Then, add the following configuration: +???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. - ```json title="tsconfig.json" - { - "compilerOptions": { - "target": "es2016", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - } -} - ``` + 1. **Generate a Solana key pair** - run the following command to create a new wallet: -4. **Install dependencies** - add the required packages + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` - ```bash - npm install @wormhole-foundation/sdk axios web3 tsx @types/node - ``` + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: - - `@wormhole-foundation/sdk` - handles VAAs and cross-chain interactions - - `axios` - makes HTTP requests to the Wormholescan API - - `web3` - interacts with Ethereum transactions and contracts - - `tsx` - executes TypeScript files without compilation - - `@types/node` - provides Node.js type definitions + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` -5. **Create the project structure** - set up the required directories and files + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: - ```bash - mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts - mkdir -p src/helpers && touch src/helpers/vaaHelper.ts - mkdir -p src/scripts && touch scripts/replaceSignatures.ts - ``` + === "Mainnet" + ```bash + solana config set -um + ``` - - **`src/config/*`** - stores public configuration variables and layouts for serializing and deserializing data structures - - **`src/helpers/*`** - contains utility functions - - **`src/scripts/*`** - contains scripts for fetching and replacing signatures + === "Testnet" + ```bash + solana config set -ut + ``` -6. **Set variables** - define key constants in `src/config/constants.ts` + === "Devnet" + ```bash + solana config set -ud + ``` - ```bash title="src/config/constants.ts" - export const RPC = 'https://ethereum-rpc.publicnode.com'; + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: -export const ETH_CORE = - '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase(); + ```bash + solana airdrop 2 + solana balance + ``` -export const WORMHOLESCAN_API = 'https://api.wormholescan.io/v1'; + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} -export const LOG_MESSAGE_PUBLISHED_TOPIC = - '0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2'; + ```bash + cargo install spl-token-cli + ``` -export const TXS = [ - '0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367', - '0x3c989a6bb40dcd4719453fbe7bbac420f23962c900ae75793124fc9cc614368c', -]; - ``` + 6. **Create a new SPL token** - initialize the token on Solana - - **`RPC`** - endpoint for interacting with an Ethereum RPC node - - **`ETH_CORE`** - [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} responsible for verifying VAAs - - **`WORMHOLESCAN_API`** - base URL for querying the Wormholescan API to fetch VAA data and Guardian sets - - **`LOG_MESSAGE_PUBLISHED_TOPIC`** - the event signature hash for `LogMessagePublished`, a Wormhole contract event that signals when a VAA has been emitted. This is used to identify relevant logs in transaction receipts - - **`TXS`** - list of example transaction hashes that will be used for testing - -7. **Define data structure for working with VAAs** - specify the ABI for the Wormhole Core Contract's `parseAndVerifyVM` function, which parses and verifies VAAs. Defining the data structure, also referred to as a [layout](/docs/tools/typescript-sdk/guides/sdk-layout/){target=\_blank}, for this function ensures accurate decoding and validation of VAAs + ```bash + spl-token create-token + ``` - ```typescript title="src/config/layouts.ts" - export const PARSE_AND_VERIFY_VM_ABI = { - inputs: [{ internalType: 'bytes', name: 'encodedVM', type: 'bytes' }], - name: 'parseAndVerifyVM', - outputs: [ - { - components: [ - { internalType: 'uint8', name: 'version', type: 'uint8' }, - { internalType: 'uint32', name: 'timestamp', type: 'uint32' }, - { internalType: 'uint32', name: 'nonce', type: 'uint32' }, - { internalType: 'uint16', name: 'emitterChainId', type: 'uint16' }, - { internalType: 'bytes32', name: 'emitterAddress', type: 'bytes32' }, - { internalType: 'uint64', name: 'sequence', type: 'uint64' }, - { internalType: 'uint8', name: 'consistencyLevel', type: 'uint8' }, - { internalType: 'bytes', name: 'payload', type: 'bytes' }, - { internalType: 'uint32', name: 'guardianSetIndex', type: 'uint32' }, - { - components: [ - { internalType: 'bytes32', name: 'r', type: 'bytes32' }, - { internalType: 'bytes32', name: 's', type: 'bytes32' }, - { internalType: 'uint8', name: 'v', type: 'uint8' }, - { internalType: 'uint8', name: 'guardianIndex', type: 'uint8' }, - ], - internalType: 'struct Structs.Signature[]', - name: 'signatures', - type: 'tuple[]', - }, - { internalType: 'bytes32', name: 'hash', type: 'bytes32' }, - ], - internalType: 'struct Structs.VM', - name: 'vm', - type: 'tuple', - }, - { internalType: 'bool', name: 'valid', type: 'bool' }, - { internalType: 'string', name: 'reason', type: 'string' }, - ], - stateMutability: 'view', - type: 'function', -}; - ``` + 7. **Create a token account** - generate an account to hold the token -## Create VAA Handling Functions + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` -In this section, we'll create a series of helper functions in the `src/helpers/vaaHelper.ts` file that will retrieve and verify VAAs and fetch and replace outdated Guardian signatures to generate a correctly signed VAA. + 8. **Mint tokens** - send 1000 tokens to the created account -To get started, import the necessary dependencies: + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` -```typescript title="src/helpers/vaaHelper.ts" -import { eth } from 'web3'; -import { - deserialize, - serialize, - VAA, - Signature, -} from '@wormhole-foundation/sdk'; -import { - RPC, - ETH_CORE, - LOG_MESSAGE_PUBLISHED_TOPIC, - WORMHOLESCAN_API, -} from '../config/constants'; -import { PARSE_AND_VERIFY_VM_ABI } from '../config/layouts'; -``` + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -### Fetch a VAA ID from a Transaction +## Install NTT CLI -To retrieve a VAA, we first need to get its VAA ID from a transaction hash. This ID allows us to fetch the full VAA later. -The VAA ID is structured as follows: +The NTT CLI is recommended to deploy and manage your cross-chain token configuration. -```bash -chain/emitter/sequence -``` +1. Run the installation command in your terminal: - - `chain` - the [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} (Ethereum is 2) - - `emitter` - the contract address that emitted the VAA - - `sequence` - a unique identifier for the event + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -We must assemble the ID correctly since this is the format the Wormholescan API expects when querying VAAs. +2. Verify the NTT CLI is installed: -Follow the below steps to process the transaction logs and construct the VAA ID: + ```bash + ntt --version + ``` -1. **Get the transaction receipt** - iterate over the array of transaction hashes and fetch the receipt to access its logs +## Initialize a New NTT Project -2. **Find the Wormhole event** - iterate over the transaction logs and check for events emitted by the Wormhole Core contract. Look specifically for `LogMessagePublished` events, which indicate a VAA was created +1. Once the CLI is installed, scaffold a new project by running: -3. **Extract the emitter and sequence number** - if a matching event is found, extract the emitter address from `log.topics[1]` and remove the `0x` prefix. Then, the sequence number from `log.data` is extracted, converting it from hex to an integer + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` -4. **Construct the VAA ID** - format the extracted data in `chain/emitter/sequence` format +2. Initialize a new `deployment.json` file specifying the network: -```typescript title="src/helpers/vaaHelper.ts" -const vaaIds: string[] = []; + === "Mainnet" + ```bash + ntt init Mainnet + ``` - for (const tx of txHashes) { - try { - const result = ( - await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_getTransactionReceipt', - params: [tx], - }) - ).data.result; + === "Testnet" + ```bash + ntt init Testnet + ``` - if (!result) - throw new Error(`Unable to fetch transaction receipt for ${tx}`); + After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. - for (const log of result.logs) { - if ( - log.address === ETH_CORE && - log.topics?.[0] === LOG_MESSAGE_PUBLISHED_TOPIC - ) { - const emitter = log.topics[1].substring(2); - const seq = BigInt(log.data.substring(0, 66)).toString(); - vaaIds.push(`2/${emitter}/${seq}`); + === "Mainnet" + ```json + { + "network": "Mainnet", + "chains": {} } - } - } catch (error) { - console.error(`Error processing ${tx}:`, error); - } - } + ``` - return vaaIds; -} -``` + === "Testnet" + ```json + { + "network": "Testnet", + "chains": {} + } + ``` -???- code "Try it out: VAA ID retrieval" - If you want to try out the function before moving forward, create a test file inside the `test` directory: +In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. - 1. **Create the directory and file** - add a script to call `fetchVaaId` and print the result +## Next Steps - ```bash - mkdir -p test - touch test/fetchVaaId.run.ts - ``` - 2. **Add the function call** +You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: - ```typescript title="test/fetchVaaId.run.ts" - import { fetchVaaId } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +--- END CONTENT --- -const testFetchVaaId = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers EVM Deployment +description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- - if (vaaIds.length > 0) { - console.log(`Transaction: ${tx}`); - vaaIds.forEach((vaaId) => console.log(`VAA ID: ${vaaId}`)); - } else { - console.log(`No VAA ID found for transaction: ${tx}`); - } - } -}; +# Native Token Transfers (NTT) EVM Development -testFetchVaaId(); - ``` +## Deploy Your Token and Ensure Compatibility - 3. **Run the script** +If you still need to do so, deploy the token contract to the destination or spoke chains. - ```bash - npx tsx test/fetchVaaId.run.ts - ``` +### Requirements for Token Deployment - If successful, the output will be: +Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. -
    -npx tsx test/fetchVaaId.run.ts - -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -VAA ID: 2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/164170 - -
    +#### Burn-and-Mint Mode - If no VAA ID is found, the script will log an error message. +Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: -### Fetch the Full VAA +- `burn(uint256 amount)` +- `mint(address account, uint256 amount)` -Now that you have the VAA ID, we can use it to fetch the full VAA payload from the Wormholescan API. This payload contains the VAA bytes, which will later be used for signature validation. +These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. -Open `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload. +??? code "View the complete `INttToken` Interface`" + ```solidity + // SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; -```typescript title="src/helpers/vaaHelper.ts" -vaaIds: string[] -): Promise<{ id: string; vaaBytes: string }[]> { - const results: { id: string; vaaBytes: string }[] = []; +interface INttToken { + /// @notice Error when the caller is not the minter. + /// @dev Selector 0x5fb5729e. + /// @param caller The caller of the function. + error CallerNotMinter(address caller); - for (const id of vaaIds) { - try { - const response = await axios.get(`${WORMHOLESCAN_API}/signed_vaa/${id}`); - const vaaBytes = response.data.vaaBytes; - results.push({ id, vaaBytes }); - } catch (error) { - console.error(`Error fetching VAA for ${id}:`, error); - } - } - return results; -} -``` + /// @notice Error when the minter is the zero address. + /// @dev Selector 0x04a208c7. + error InvalidMinterZeroAddress(); -???- code "Try it out: VAA retrieval" - If you want to try the function before moving forward, create a script inside the `test` directory + /// @notice Error when insufficient balance to burn the amount. + /// @dev Selector 0xcf479181. + /// @param balance The balance of the account. + /// @param amount The amount to burn. + error InsufficientBalance(uint256 balance, uint256 amount); - 1. **Create the script file** + /// @notice The minter has been changed. + /// @dev Topic0 + /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. + /// @param newMinter The new minter. + event NewMinter(address previousMinter, address newMinter); - ```bash - touch test/fetchVaa.run.ts - ``` + // NOTE: the `mint` method is not present in the standard ERC20 interface. + function mint(address account, uint256 amount) external; - 2. **Add the function call** + // NOTE: the `setMinter` method is not present in the standard ERC20 interface. + function setMinter(address newMinter) external; - ```typescript title="test/fetchVaa.run.ts" - import { fetchVaaId, fetchVaa } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; + // NOTE: NttTokens in `burn` mode require the `burn` method to be present. + // This method is not present in the standard ERC20 interface, but is + // found in the `ERC20Burnable` interface. + function burn(uint256 amount) external; +} + ``` -const testFetchVaa = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); +Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } +#### Hub-and-Spoke Mode - for (const vaaId of vaaIds) { - const vaaBytes = await fetchVaa([vaaId]); +A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Bytes: ${ - vaaBytes.length > 0 ? vaaBytes[0].vaaBytes : 'Not found' - }` - ); - } - } -}; + - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains + - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers -testFetchVaa(); - ``` +!!! note + The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. - 3. **Run the script** +For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. - ```bash - npx tsx test/fetchVaa.run.ts - ``` +This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. - If successful, the output will be: +For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. -
    -npx tsx test/fetchVaa.run.ts - -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -VAA Bytes: AQAAAAMNANQSwD/HRPcKp7Yxypl1ON8dZeMBzgYJrd2KYz6l9Tq9K9fj72fYJgkMeMaB9h... - -
    +### Key Differences Between Modes - If no VAA is found, the script will log an error message. + - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently + - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency -### Validate VAA Signatures +## Deploy NTT -Now, we need to verify its validity. A VAA is only considered valid if it contains signatures from currently active Guardians and is correctly verified by the Wormhole Core contract. +Create a new NTT project: -Open `src/helpers/vaaHelper.ts` and add the `checkVaaValidity()` function. This function verifies whether a VAA is valid by submitting it to an Ethereum RPC node and checking for outdated signatures. +```bash +ntt new my-ntt-deployment +cd my-ntt-deployment +``` -Follow these steps to implement the function: +Initialize a new `deployment.json` file specifying the network: -1. **Prepare the VAA for verification** - construct the VAA payload in a format that can be sent to the Wormhole Core contract +=== "Testnet" -2. **Send an `eth_call` request** - submit the VAA to an Ethereum RPC node, calling the `parseAndVerifyVM` function on the Wormhole Core contract + ```bash + ntt init Testnet + ``` -3. **Decode the response** - check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them +=== "Mainnet" -```typescript title="src/helpers/vaaHelper.ts" -try { - const vaa = Buffer.from(vaaBytes, 'base64'); - vaa[4] = 4; // Set guardian set index to 4 + ```bash + ntt init Mainnet + ``` - const result = ( - await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [ - `0x${vaa.toString('hex')}`, - ]), - }, - 'latest', - ], - }) - ).data.result; +Ensure you have set up your environment correctly: - const decoded = eth.abi.decodeParameters( - PARSE_AND_VERIFY_VM_ABI.outputs, - result - ); - console.log( - `${decoded.valid ? '✅' : '❌'} VAA Valid: ${decoded.valid}${ - decoded.valid ? '' : `, Reason: ${decoded.reason}` - }` - ); +```bash +export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY +``` - return { valid: decoded.valid, reason: decoded.reason }; - } catch (error) { - console.error(`Error checking VAA validity:`, error); - return { valid: false, reason: 'RPC error' }; - } -} +Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: + +```bash +# Set scanner API Keys as environment variables +export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY +export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY + +# Add each chain +# The contracts will be automatically verified using the scanner API keys above +ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS +ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS ``` -???- code "Try it out: VAA Validity" - If you want to try the function before moving forward, create a script inside the `test` directory +While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. - 1. **Create the script file** +The `ntt add-chain` command takes the following parameters: - ```bash - touch test/checkVaaValidity.run.ts - ``` +- Name of each chain +- Version of NTT to deploy (use `--latest` for the latest contract versions) +- Mode (either `burning` or `locking`) +- Your token contract address - 2. **Add the function call** +The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. - ```typescript title="test/checkVaaValidity.run.ts" - import { - fetchVaaId, - fetchVaa, - checkVaaValidity, -} from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; +## Configure NTT -const testCheckVaaValidity = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); +The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } +- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain +- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: - for (const vaaId of vaaIds) { - const vaaData = await fetchVaa([vaaId]); + For Solana, the limits are set with 9 decimal places: + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + } + ``` - if (vaaData.length === 0 || !vaaData[0].vaaBytes) { - console.log(`VAA not found for ID: ${vaaId}`); - continue; + For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: + ```json + "inbound": { + "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia } + ``` - const result = await checkVaaValidity(vaaData[0].vaaBytes); - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nVAA Validity:`, - result - ); - } - } -}; + This initial configuration ensures that the rate limits are correctly represented for each chain's token precision + +- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file -testCheckVaaValidity(); - ``` +After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. - 3. **Run the script** +## Set Token Minter to NTT Manager - ```bash - npx tsx test/checkVaaValidity.run.ts - ``` +The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. - If the VAA is valid, the output will be: +!!! note + The required NTT Manager address can be found in the `deployment.json` file. -
    -npx tsx test/checkVaaValidity.run.ts - -✅ VAA Valid: true - -
    +- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function + ```json + cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL + ``` - If invalid, the output will include the reason: +- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter -
    -npx tsx test/checkVaaValidity.run.ts - -❌ VAA Valid: false, Reason: VM signature invalid -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 - -
    +By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. -### Fetch Observations (VAA Signatures) +!!!important + To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. +--- END CONTENT --- -Before replacing outdated signatures, we need to fetch the original VAA signatures from Wormholescan. This allows us to compare them with the latest Guardian set and determine which ones need updating. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Solana Deployment +description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. +categories: NTT, Transfer +--- -Inside `src/helpers/vaaHelper.ts`, create the `fetchObservations()` function to query the Wormholescan API for observations related to a given VAA. Format the response by converting Guardian addresses to lowercase for consistency, and return an empty array if an error occurs. +# Deploy Native Token Transfers on Solana -```typescript title="src/helpers/vaaHelper.ts" -try { - console.log(`Fetching observations`); +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. - const response = await axios.get( - `https://api.wormholescan.io/api/v1/observations/${vaaId}` - ); +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - return response.data.map((obs: any) => ({ - guardianAddr: obs.guardianAddr.toLowerCase(), - signature: obs.signature, - })); - } catch (error) { - console.error(`Error fetching observations:`, error); - return []; - } -} -``` +The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. -???- code "Try it out: Fetch Observations" - If you want to try the function before moving forward, create a script inside the `test` directory +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) - 1. **Create the script file** +By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. - ```bash - touch test/fetchObservations.run.ts - ``` - 2. **Add the function call** +## Prerequisites - ```typescript title="test/fetchObservations.run.ts" - import { fetchVaaId, fetchObservations } from '../src/helpers/vaaHelper'; -import { TXS } from '../src/config/constants'; +Before deploying NTT on Solana, ensure you have the following: -const testFetchObservations = async () => { - for (const tx of TXS) { - const vaaIds = await fetchVaaId([tx]); +- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} +- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** +- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** - if (vaaIds.length === 0) { - console.log(`No VAA ID found for transaction: ${tx}`); - continue; - } +Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. - for (const vaaId of vaaIds) { - const observations = await fetchObservations(vaaId); +## Overview of the Deployment Process - if (observations.length === 0) { - console.log(`No observations found for VAA ID: ${vaaId}`); - continue; - } +Deploying NTT with the CLI on Solana follows a structured process: - console.log( - `Transaction: ${tx}\nVAA ID: ${vaaId}\nObservations:`, - observations - ); - } - } -}; +1. **Choose your token setup**: -testFetchObservations(); - ``` + - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section + - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT - 3. **Run the script** + ???- interface "Create and Mint SPL Tokens" + This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. - ```bash - npx tsx test/fetchObservations.run.ts - ``` + 1. **Generate a Solana key pair** - run the following command to create a new wallet: - If successful, the output will be: + ```bash + solana-keygen grind --starts-with w:1 --ignore-case + ``` -
    -npx tsx test/fetchObservations.run.ts - -Fetching observations -Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -Observations: [ { guardianAddr: '0xda798f6896a3331f64b48c12d1d57fd9cbe70811', signature: - 'ZGFlMDYyOGNjZjFjMmE0ZTk5YzE2OThhZjAzMDM4NzZlYTM1OWMxMzczNDA3YzdlMDMxZTkyNzk0ODkwYjRiYjRiOWFmNzM3NjRiMzIyOTE0ZTQwYzNlMjllMWEzNmM2NTc3ZDc5ZTdhNTM2MzA5YjA4YjExZjE3YzE3MDViNWIwMQ==' - }, { guardianAddr: '0x74a3bf913953d695260d88bc1aa25a4eee363ef0', signature: - 'MzAyOTU4OGU4MWU0ODc0OTAwNDU3N2EzMGZlM2UxMDJjOWYwMjM0NWVhY2VmZWQ0ZGJlNTFkNmI3YzRhZmQ5ZTNiODFjNTg3MDNmYzUzNmJiYWFiZjNlODc1YTY3OTQwMGE4MmE3ZjZhNGYzOGY3YmRmNDNhM2VhNGQyNWNlNGMwMA==' - }, -...] - -
    + 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: - If no observations are found, the script will log an error message. + ```bash + solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON + ``` -### Fetch the Latest Guardian Set + 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: -Now that we have the original VAA signatures, we must fetch the latest Guardian set from Wormholescan. This will allow us to compare the stored signatures with the current Guardians and determine which signatures need replacing. + === "Mainnet" + ```bash + solana config set -um + ``` -Create the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set. + === "Testnet" + ```bash + solana config set -ut + ``` -```typescript title="src/helpers/vaaHelper.ts" -export async function fetchGuardianSet() { - try { - console.log('Fetching current guardian set'); + === "Devnet" + ```bash + solana config set -ud + ``` - const response = await axios.get(`${WORMHOLESCAN_API}/guardianset/current`); - const guardians = response.data.guardianSet.addresses.map((addr: string) => - addr.toLowerCase() - ); - const guardianSet = response.data.guardianSet.index; + 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: - return [guardians, guardianSet]; - } catch (error) { - console.error('Error fetching guardian set:', error); - return []; - } -} -``` + ```bash + solana airdrop 2 + solana balance + ``` -???- code "Try it out: Fetch Guardian Set" - If you want to try the function before moving forward, create a script inside the `test` directory + 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} - 1. **Create the script file** + ```bash + cargo install spl-token-cli + ``` - ```bash - touch test/fetchGuardianSet.run.ts - ``` + 6. **Create a new SPL token** - initialize the token on Solana - 2. **Add the function call** + ```bash + spl-token create-token + ``` - ```typescript title="test/fetchGuardianSet.run.ts" - import { fetchGuardianSet } from '../src/helpers/vaaHelper'; + 7. **Create a token account** - generate an account to hold the token -const testFetchGuardianSet = async () => { - const [guardians, guardianSetIndex] = await fetchGuardianSet(); + ```bash + spl-token create-account INSERT_TOKEN_ADDRESS + ``` - console.log('Current Guardian Set Index:', guardianSetIndex); - console.log('Guardian Addresses:', guardians); -}; + 8. **Mint tokens** - send 1000 tokens to the created account -testFetchGuardianSet(); - ``` + ```bash + spl-token mint INSERT_TOKEN_ADDRESS 1000 + ``` - 3. **Run the script** + !!! note + NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. - ```bash - npx tsx test/fetchGuardianSet.run.ts - ``` +2. **Choose your [deployment model](TODO){target=\_blank}**: - If successful, the output will be: + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program -
    -npx tsx test/fetchGuardianSet.run.ts - -Fetching current guardian set -Current Guardian Set Index: 4 -Guardian Addresses: [ - '0x5893b5a76c3f739645648885bdccc06cd70a3cd3', - '0xff6cb952589bde862c25ef4392132fb9d4a42157', - '0x114de8460193bdf3a2fcf81f86a09765f4762fd1', - '0x107a0086b32d7a0977926a205131d8731d39cbeb', - -...] - -
    +3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode - If an error occurs while fetching the Guardian set, a `500` status error will be logged. +Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. -### Replace Outdated Signatures +By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. -With the full VAA, Guardian signatures, and the latest Guardian set, we can now update outdated signatures while maintaining the required signature count. +## Set Up NTT -1. **Create the `replaceSignatures()` function** - open `src/helpers/vaaHelper.ts` and add the function header. To catch and handle errors properly, all logic will be wrapped inside a `try` block +To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. - ```typescript title="src/helpers/vaaHelper.ts" - vaa: string | Uint8Array, - observations: { guardianAddr: string; signature: string }[], - currentGuardians: string[], - guardianSetIndex: number -) { - console.log('Replacing Signatures...'); +The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: - try { - // Add logic in the following steps here - console.error('Unexpected error in replaceSignatures:', error); - } -} +1. **Create a new NTT project** - set up a deployment workspace + + ```bash + ntt new INSERT_PROJECT_NAME + cd INSERT_PROJECT_NAME ``` - - **`vaa`** - original VAA bytes - - **`observations`** - observed signatures from the network - - **`currentGuardians`** - latest Guardian set - - **`guardianSetIndex`** - current Guardian set index +2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings -2. **Validate input data** - ensure all required parameters are present before proceeding. If any required input is missing, the function throws an error to prevent execution with incomplete data. The Guardian set should never be empty; if it is, this likely indicates an error in fetching the Guardian set in a previous step + === "Mainnet" - ```typescript - if (currentGuardians.length === 0) - throw new Error('Guardian set is empty.'); - if (observations.length === 0) throw new Error('No observations provided.'); - ``` + ```bash + ntt init Mainnet + ``` -3. **Filter valid signatures** - remove signatures from inactive Guardians, keeping only valid ones. If there aren't enough valid signatures to replace the outdated ones, execution is halted to prevent an incomplete or invalid VAA + === "Testnet" - ```typescript - currentGuardians.includes(sig.guardianAddr) - ); + ```bash + ntt init Testnet + ``` +!!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. - if (validSigs.length === 0) - throw new Error('No valid signatures found. Cannot proceed.'); - ``` +### Generate an NTT Program Key Pair -4. **Convert valid signatures** - ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components +Create a unique key pair for the NTT program: - ```typescript - .map((sig) => { - try { - const sigBuffer = Buffer.from(sig.signature, 'base64'); - // If it's 130 bytes, it's hex-encoded and needs conversion - const sigBuffer1 = - sigBuffer.length === 130 - ? Buffer.from(sigBuffer.toString(), 'hex') - : sigBuffer; +```bash +solana-keygen grind --starts-with ntt:1 --ignore-case +``` - const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); - const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); - const vRaw = sigBuffer1[64]; - const v = vRaw < 27 ? vRaw : vRaw - 27; +### Set Mint Authority - return { - guardianIndex: currentGuardians.indexOf(sig.guardianAddr), - signature: new Signature(r, s, v), - }; - } catch (error) { - console.error( - `Failed to process signature for guardian: ${sig.guardianAddr}`, - error - ); - return null; - } - }) - .filter( - (sig): sig is { guardianIndex: number; signature: Signature } => - sig !== null - ); // Remove null values +If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. + +If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). + +Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. + +Follow these steps to set the mint authority using the NTT CLI: + +1. **Derive the token authority** - generate the PDA, which will manage token minting + + ```bash + ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR ``` -5. **Deserialize the VAA** - convert the raw VAA data into a structured format for further processing +2. **Set SPL token mint authority** - delegate minting control to the derived PDA - ```typescript - try { - parsedVaa = deserialize('Uint8Array', vaa); - } catch (error) { - throw new Error(`Error deserializing VAA: ${error}`); - } + ```bash + spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA ``` -6. **Identify outdated signatures** - compare the current VAA signatures with the newly formatted ones to detect which signatures belong to outdated Guardians. Remove these outdated signatures to ensure only valid ones remain +## Deploy and Configure NTT - ```typescript - .filter( - (vaaSig) => - !formattedSigs.some( - (sig) => sig.guardianIndex === vaaSig.guardianIndex - ) - ) - .map((sig) => sig.guardianIndex); +!!! warning + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. - console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); - let updatedSignatures = parsedVaa.signatures.filter( - (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) - ); - ``` +After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: -7. **Replace outdated signatures** - substitute outdated signatures with valid ones while maintaining the correct number of signatures. If there aren’t enough valid replacements, execution stops +1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: - ```typescript - (sig) => - !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) - ); + === "Burn-and-Mint" - // Check if we have enough valid signatures to replace outdated ones** - if (outdatedGuardianIndexes.length > validReplacements.length) { - console.warn( - `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` - ); - return; - } + ```bash + ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` - updatedSignatures = [ - ...updatedSignatures, - ...validReplacements.slice(0, outdatedGuardianIndexes.length), - ]; + === "Hub-and-Spoke" - updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); - ``` + ```bash + ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON + ``` -8. **Serialize the updated VAA** - reconstruct the VAA with the updated signatures and convert it into a format suitable for submission + You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. - ```typescript - ...parsedVaa, - guardianSet: guardianSetIndex, - signatures: updatedSignatures, - }; +2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: - let patchedVaa: Uint8Array; - try { - patchedVaa = serialize(updatedVaa); - } catch (error) { - throw new Error(`Error serializing updated VAA: ${error}`); - } + ```bash + ntt status ``` -9. **Send the updated VAA for verification and handle errors** - submit the updated VAA to an Ethereum RPC node for validation, ensuring it can be proposed for Guardian approval. If an error occurs during submission or signature replacement, log the issue and prevent further execution - - ```typescript - if (!(patchedVaa instanceof Uint8Array)) - throw new Error('Patched VAA is not a Uint8Array!'); + If needed, sync your local configuration with the on-chain state: - const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; + ```bash + ntt pull + ``` - console.log('Sending updated VAA to RPC...'); +3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. - const result = await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), - }, - 'latest', - ], - }); + Open your `deployment.json` file and adjust the values based on your use case: - const verificationResult = result.data.result; - console.log('Updated VAA (hex):', vaaHex); - return verificationResult; - } catch (error) { - throw new Error(`Error sending updated VAA to RPC: ${error}`); + ```json + "inbound": { + "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana + }, + "outbound": { + "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia } ``` -???- code "Complete Function" - ```typescript - vaa: string | Uint8Array, - observations: { guardianAddr: string; signature: string }[], - currentGuardians: string[], - guardianSetIndex: number -) { - console.log('Replacing Signatures...'); +4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees - try { - if (!vaa) throw new Error('VAA is undefined or empty.'); - if (currentGuardians.length === 0) - throw new Error('Guardian set is empty.'); - if (observations.length === 0) throw new Error('No observations provided.'); + ```bash + ntt push --payer INSERT_YOUR_KEYPAIR_JSON + ``` - const validSigs = observations.filter((sig) => - currentGuardians.includes(sig.guardianAddr) - ); +### Troubleshoot Deployment Issues + +If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. - if (validSigs.length === 0) - throw new Error('No valid signatures found. Cannot proceed.'); +## Where to Go Next - const formattedSigs = validSigs - .map((sig) => { - try { - const sigBuffer = Buffer.from(sig.signature, 'base64'); - // If it's 130 bytes, it's hex-encoded and needs conversion - const sigBuffer1 = - sigBuffer.length === 130 - ? Buffer.from(sigBuffer.toString(), 'hex') - : sigBuffer; +
    - const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex')); - const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex')); - const vRaw = sigBuffer1[64]; - const v = vRaw < 27 ? vRaw : vRaw - 27; +- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** - return { - guardianIndex: currentGuardians.indexOf(sig.guardianAddr), - signature: new Signature(r, s, v), - }; - } catch (error) { - console.error( - `Failed to process signature for guardian: ${sig.guardianAddr}`, - error - ); - return null; - } - }) - .filter( - (sig): sig is { guardianIndex: number; signature: Signature } => - sig !== null - ); // Remove null values + --- - let parsedVaa: VAA<'Uint8Array'>; - try { - parsedVaa = deserialize('Uint8Array', vaa); - } catch (error) { - throw new Error(`Error deserializing VAA: ${error}`); - } + After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - const outdatedGuardianIndexes = parsedVaa.signatures - .filter( - (vaaSig) => - !formattedSigs.some( - (sig) => sig.guardianIndex === vaaSig.guardianIndex - ) - ) - .map((sig) => sig.guardianIndex); + [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes); +- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** - let updatedSignatures = parsedVaa.signatures.filter( - (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex) - ); + --- - const validReplacements = formattedSigs.filter( - (sig) => - !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex) - ); + Follow the NTT Post Deployment Guide for integration examples and testing instructions. - // Check if we have enough valid signatures to replace outdated ones** - if (outdatedGuardianIndexes.length > validReplacements.length) { - console.warn( - `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.` - ); - return; - } + [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} - updatedSignatures = [ - ...updatedSignatures, - ...validReplacements.slice(0, outdatedGuardianIndexes.length), - ]; +- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** - updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex); + --- - const updatedVaa: VAA<'Uint8Array'> = { - ...parsedVaa, - guardianSet: guardianSetIndex, - signatures: updatedSignatures, - }; + Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. - let patchedVaa: Uint8Array; - try { - patchedVaa = serialize(updatedVaa); - } catch (error) { - throw new Error(`Error serializing updated VAA: ${error}`); - } + [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} - try { - if (!(patchedVaa instanceof Uint8Array)) - throw new Error('Patched VAA is not a Uint8Array!'); +- :octicons-question-16:{ .lg .middle } **View FAQs** - const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`; + --- - console.log('Sending updated VAA to RPC...'); + Find answers to common questions about NTT. - const result = await axios.post(RPC, { - jsonrpc: '2.0', - id: 1, - method: 'eth_call', - params: [ - { - from: null, - to: ETH_CORE, - data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]), - }, - 'latest', - ], - }); + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - const verificationResult = result.data.result; - console.log('Updated VAA (hex):', vaaHex); - return verificationResult; - } catch (error) { - throw new Error(`Error sending updated VAA to RPC: ${error}`); - } - } catch (error) { - console.error('Unexpected error in replaceSignatures:', error); - } -} - ``` +- :octicons-question-16:{ .lg .middle } **View FAQs** -## Create Script to Replace Outdated VAA Signatures + --- -Now that we have all the necessary helper functions, we will create a script to automate replacing outdated VAA signatures. This script will retrieve a transaction’s VAA sequentially, check its validity, fetch the latest Guardian set, and update its signatures. By the end, it will output a correctly signed VAA that can be proposed for Guardian approval. + Find answers to common questions about NTT. -1. **Open the file** - inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - ```typescript title="src/scripts/replaceSignatures.ts" - fetchVaaId, - fetchVaa, - checkVaaValidity, - fetchObservations, - fetchGuardianSet, - replaceSignatures, -} from '../helpers/vaaHelper'; -import { TXS } from '../config/constants'; - ``` +
    +--- END CONTENT --- -2. **Define the main execution function** - add the following function inside `src/scripts/replaceSignatures.ts` to process each transaction in `TXS`, going step by step through the signature replacement process +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +--- BEGIN CONTENT --- +--- +title: Deploy Native Token Transfers with Launchpad +description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +categories: NTT, Transfer +--- - ```typescript - try { - for (const tx of TXS) { - console.log(`\nProcessing TX: ${tx}\n`); +# Deploy Native Token Transfers with Launchpad - // 1. Fetch Transaction VAA IDs: - const vaaIds = await fetchVaaId([tx]); - if (!vaaIds.length) continue; +## Introduction - // 2. Fetch VAA Data: - const vaaData = await fetchVaa(vaaIds); - if (!vaaData.length) continue; +The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. - const vaaBytes = vaaData[0].vaaBytes; - if (!vaaBytes) continue; +Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. - // 3. Check VAA Validity: - const { valid } = await checkVaaValidity(vaaBytes); - if (valid) continue; +The Launchpad automates deployment, reducing complexity and saving time. - // 4. Fetch Observations (VAA signatures): - const observations = await fetchObservations(vaaIds[0]); +This guide covers: - // 5. Fetch Current Guardian Set: - const [currentGuardians, guardianSetIndex] = await fetchGuardianSet(); + - Launching a new cross-chain token + - Expanding an existing token for NTT + - Managing tokens via the dashboard and settings - // 6. Replace Signatures: - const response = await replaceSignatures( - Buffer.from(vaaBytes, 'base64'), - observations, - currentGuardians, - guardianSetIndex - ); +## Prerequisites - if (!response) continue; - } - } catch (error) { - console.error('❌ Error in execution:', error); - process.exit(1); - } -} - ``` + - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) + - Minimum ETH (or equivalent) for gas fees per deployment -3. **Make the script executable** - ensure it runs when executed +## Supported Blockchains - ```typescript - - ``` +The NTT Launchpad currently supports deployments on the following mainnet chains: - To run the script, use the following command: + - Ethereum + - Arbitrum One + - Base + - Berachain + - Blast + - BNB Smart Chain + - Ink + - Optimism Mainnet + - Polygon - ```bash - npx tsx src/scripts/replaceSignatures.ts - ``` +## Choose Your Path -
    -npx tsx src/scripts/replaceSignatures.ts - -Processing TX: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367 -❌ VAA Valid: false, Reason: VM signature invalid -Fetching observations -Fetching current guardian set -Replacing Signatures... -Outdated Guardian Indexes: [ 0 ] -Sending updated VAA to RPC... -Updated VAA (hex): 0x01000000040d010019447b72d51e33923a3d6b28496ccd3722d5f1e33e2... - -
    +Once ready, choose an option to proceed: -The script logs each step, skipping valid VAAs, replacing outdated signatures for invalid VAAs, and logging any errors. It then completes with a valid VAA ready for submission. + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains + - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract -## Resources +## Launch a Cross-Chain Token -You can explore the complete project and find all necessary scripts and configurations in Wormhole's [demo GitHub repository](https://github.com/wormhole-foundation/demo-vaa-signature-replacement){target=\_blank}. +Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: -The demo repository includes a bonus script to check the VAA redemption status on Ethereum and Solana, allowing you to verify whether a transaction has already been redeemed on the destination chain. +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** -## Conclusion + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) + +2. Select **Launch a Cross-Chain Token** -You've successfully built a script to fetch, validate, and replace outdated signatures in VAAs using Wormholescan and the Wormhole SDK. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) -It's important to note that this tutorial does not update VAAs in the Wormhole network. Before redeeming the VAA, you must propose it for Guardian approval to finalize the process. ---- END CONTENT --- +3. Set the token details: + 1. Select the **home network** from the dropdown menu + 2. Enter the **name** for the token + 3. Enter the **symbol** of the token + 4. Provide the **initial supply** + 5. To the token details, click **Next** -Doc-Content: https://wormhole.com/docs/products/multigov/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: MultiGov Architecture -description: Discover MultiGov's hub-and-spoke architecture, enabling secure cross-chain governance with Wormhole’s interoperability and decentralized coordination. -categories: MultiGov ---- + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) -# MultiGov Architecture +4. Select the deployment chains: + 1. The home network where your token will be deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** -MultiGov uses a hub-and-spoke architecture to coordinate governance across multiple blockchains. The hub chain is the central controller that handles proposal creation, vote aggregation, and execution. Spoke chains allow token holders to vote locally and can also execute proposal outcomes specific to their network. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) -Wormhole’s multichain messaging infrastructure connects the hub and spokes, enabling secure and efficient chain communication. This design allows DAOs to operate seamlessly across ecosystems while maintaining a unified governance process. +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction -The diagram below illustrates this high-level architecture. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) -![High-level architecture diagram illustrating the hub-and-spoke structure of the MultiGov system. The diagram shows three key components: Hub Chain and two Spoke Chains, interconnected via Wormhole for cross-chain governance.](/docs/images/products/multigov/concepts/architecture/architecture-1.webp) +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet -## Key Components + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -### Hub Chain Contracts +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step -The hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains. +8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. - - **`HubGovernor`** - central governance contract managing proposals and vote tallying - - **`HubVotePool`** - receives aggregated votes from spokes and submits them to `HubGovernor` - - **`HubMessageDispatcher`** - relays approved proposal executions to spoke chains - - **`HubProposalExtender`** - allows trusted actors to extend voting periods if needed - - **`HubProposalMetadata`** - helper contract returning `proposalId` and vote start for `HubGovernor` proposals - - **`HubEvmSpokeAggregateProposer`** - aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible +## Expand Your Existing Token -### Spoke Chains Contracts +Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: -Spoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance. +1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** - - **`SpokeVoteAggregator`** - collects votes on the spoke chain and forwards them to the hub - - **`SpokeMessageExecutor`** - receives and executes approved proposals from the hub - - **`SpokeMetadataCollector`** - fetches proposal metadata from the hub for spoke chain voters - - **`SpokeAirlock`** - acts as governance's "admin" on the spoke, has permissions, and its treasury + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) -### Spoke Solana Staking Program +2. Select **Expand Your Existing Token** -The Spoke Solana Staking Program handles local voting from users who have staked W tokens or are vested in the program, forwards votes to the hub, and executes approved proposals from the hub for decentralized governance. + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) -The program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program: +3. Enter the token details: + 1. Choose the home network where your token is already deployed (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 3. To continue, click **Next** - - **`GlobalConfig`** - global program configuration - - **`StakeAccountMetadata`** - stores user's staking information - - **`CustodyAuthority`** - PDA account managing custody and overseeing token operations related to stake accounts - - **`StakeAccountCustody`** - token account associated with a stake account for securely storing staked tokens - - **`CheckpointData`** - tracks delegation history - - **`SpokeMetadataCollector`** - collects and updates proposal metadata from the hub chain - - **`GuardianSignatures`** - stores guardian signatures for message verification - - **`ProposalData`** - stores data about a specific proposal, including votes and start time - - **`ProposalVotersWeightCast`** - tracks individual voter's weight for a proposal - - **`SpokeMessageExecutor`** - processes messages from a spoke chain via the Wormhole protocol - - **`SpokeAirlock`** - manages PDA signing and seed validation for secure instruction execution - - **`VestingBalance`** - stores total vesting balance and related staking information of a vester - - **`VestingConfig`** - defines vesting configuration, including mint and admin details - - **`Vesting`** - represents individual vesting allocations with maturation data - - **`VoteWeightWindowLengths`** - tracks lengths of vote weight windows + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) -Each account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management. +4. Select the chains to deploy your token to: + 1. The home network where your token is already deployed will be populated (e.g., Optimism) + 2. Choose any additional chains to deploy your token to (e.g., Base) + 1. Click **Next** -## System Workflow + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) -The MultiGov system workflow details the step-by-step process for creating, voting on, and executing governance proposals across connected chains, from proposal creation to final cross-chain execution. +5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction -### EVM Governance Workflow + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) -The EVM-based MultiGov workflow follows these steps: +6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet -1. **Proposal creation**: - 1. A user creates a proposal through the `HubEvmSpokeAggregateProposer`, which checks eligibility across chains, or directly on the `HubGovernor` via the `propose` method - 2. The proposal is submitted to the `HubGovernor` if the user meets the proposal threshold -2. **Proposal metadata distribution**: - 1. `HubProposalMetadata` creates a custom view method to be queried for use in the `SpokeMetadataCollector` - 2. `SpokeMetadataCollector` on each spoke chain queries `HubProposalMetadata` for proposal details -3. **Voting process**: - 1. Users on spoke chains vote through their respective `SpokeVoteAggregators` - 2. `SpokeVoteAggregators` send aggregated votes to the `HubVotePool` via Wormhole - 3. `HubVotePool` submits the aggregated votes to the `HubGovernor` -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached and there are more for votes than against votes, the vote passes and is queued for execution - 3. After the timelock delay, the proposal can be executed on the hub chain - 4. For cross-chain actions, a proposal should call the `dispatch` method in the `HubMessageDispatcher`, which sends execution messages to the relevant spoke chains - 5. `SpokeMessageExecutors` on each spoke chain receive and execute the approved actions through their respective `SpokeAirlocks` + ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) -### Solana Governance Workflow +7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step -The Solana-based MultiGov workflow follows these steps: - -1. **Proposal creation**: - 1. A user creates a proposal on `HubGovernor` by calling the `propose` method, provided they meet the proposal threshold - 2. For the proposal to be executed on the Solana blockchain, a `SolanaPayload` must be generated and included in the `calldata` parameter of the `propose` function - 3. The `SolanaPayload` contains encoded details specifying which instructions will be executed and which Solana program is responsible for execution - -2. **Proposal metadata distribution**: - 1. A user queries `getProposalMetadata` from `HubProposalMetadata` via the Wormhole query system to create a proposal on the **Spoke Solana Chain Staking Program** - 2. The retrieved metadata is used in the `AddProposal` instruction in the Solana program - 3. The proposal data is verified to ensure it matches the expected format - 4. Guardian signatures are posted using the `PostSignatures` instruction - 5. Once validated, the proposal is stored on-chain - -3. **Voting process**: - 1. Users vote on proposals stored in the `ProposalData` account on Solana - 2. The `CastVote` instruction records their choice (`for_votes`, `against_votes`, or `abstain_votes`) - 3. Eligibility and vote weight are verified using historical voter checkpoint data - 4. A **Query Wormhole** request retrieves vote data from a Solana PDA - 5. The signed response from Wormhole guardians is submitted to the `HubVotePool` on Ethereum for verification - 6. The `crossChainVote` function in `HubVotePool` processes the validated response and forwards the aggregated vote data to the `HubGovernor` to finalize the decision - -4. **Vote tallying and proposal execution**: - 1. `HubGovernor` tallies votes from all chains - 2. If a quorum is reached with more **for votes** than **against votes**, the proposal passes and is queued for execution - 3. After the timelock delay, the proposal can be executed either on the hub chain or another chain - 4. For cross-chain execution involving Solana, the proposal calls the `dispatch` method in `HubSolanaMessageDispatcher`, which sends execution messages to Solana - 5. On Solana, the `ReceiveMessage` instruction processes the approved message, and the `SpokeAirlock` executes the corresponding instructions - -## Cross-Chain Communication - -MultiGov relies on Wormhole's infrastructure for all cross-chain messaging, ensuring secure and reliable communication between chains. Wormhole's cross-chain state read system, known as Queries, is used for vote aggregation and proposal metadata. Additionally, cross-chain proposal execution messages are transmitted through Wormhole's custom relaying system, enabling seamless coordination across multiple blockchain networks. - -## Security Measures - -- **Vote weight window** - implements a moving window for vote weight checkpoints to mitigate cross-chain double voting - - **Proposal extension** - `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions -- **Timelock** - a timelock period between proposal approval and execution allows for additional security checks and community review -- **Wormhole verification** - all cross-chain messages are verified using Wormhole's secure messaging protocol +8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details -## Detailed Architecture Diagram +## Explore the Launchpad Dashboard -This architecture ensures that MultiGov can operate securely and efficiently across multiple chains, allowing for truly decentralized and cross-chain governance while maintaining a unified decision-making process. +To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. - -![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp) ---- END CONTENT --- +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) -Doc-Content: https://wormhole.com/docs/products/multigov/faqs/ ---- BEGIN CONTENT --- ---- -title: MultiGov FAQs -description: Find answers to common questions about MultiGov, covering cross-chain governance, technical setup, security, proposal creation, and more. -categories: MultiGov ---- +The dashboard provides a high-level view of your token across all deployed chains, including: -# FAQs + - Token addresses for each chain + - Supply distribution visualization + - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) -## What is MultiGov? +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) -MultiGov is a cross-chain governance system that extends traditional DAO governance across multiple blockchain networks. It leverages Wormhole's interoperability infrastructure for seamless voting and proposal mechanisms across various chains. +## Settings -## How does MultiGov ensure security in cross-chain communication? +The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. -MultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures: +### Chain Management -- Message origin verification to prevent unauthorized governance actions -- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states -- Authorized participant validation to maintain the integrity of the governance process -- Replay attack prevention by tracking executed messages +Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. -## Can MultiGov integrate with any blockchain? +From this section, you can also: -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. + - **Pause the token** – temporarily turn off transfers on the selected chain + - **Deploy to a new chain** – expand your token by deploying it to an additional chain -## How are votes aggregated across different chains? +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) -Votes are collected on each spoke chain using each chain's `SpokeVoteAggregator`. These votes are then transmitted to the HubVotePool on the hub chain for aggregation and tabulation. The `HubEvmSpokeVoteDecoder` standardizes votes from different EVM chains to ensure consistent processing. +### Role Management -## Can governance upgrade from a single chain to MultiGov? +This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. -Yes! MultiGov can support progressively upgrading from a single-chain governance to MultiGov. Moving to MultiGov requires upgrading the token to NTT and adding Flexible Voting to the original Governor. + - **Manager’s Owner** – the owner through the `NTTOwner` proxy + - **Pauser** – the address authorized to pause transfers -## How can I create a proposal in MultiGov? +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) -Proposals are created on the hub chain using the `HubEvmSpokeAggregateProposer` contract or by calling `propose` on the `HubGovernor`. You need to prepare the proposal details, including targets, values, and calldatas. The proposer's voting weight is aggregated across chains using Wormhole queries to determine eligibility. +### Security Threshold -## How do I vote on a proposal if I hold tokens on a spoke chain? +Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. -You can vote on proposals via the `SpokeVoteAggregator` contract on the respective spoke chain where you hold your tokens. The votes are then automatically forwarded to the hub chain for aggregation. +A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. -## How are approved proposals executed across multiple chains? + - **Registered Transceivers** – displays the number of registered transceivers and their addresses + - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers -When a proposal is approved and the timelock period elapses, it's first executed on the hub chain. A proposal can include a cross-chain message by including a call to `dispatch` on the `HubMessageDispatcher`, which sends a message to the relevant spoke chains. On each spoke chain, the `SpokeMessageExecutor` receives, verifies, and automatically executes the instructions using the `SpokeAirlock` as the `msg.sender`. +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) -## What are the requirements for using MultiGov? +### Peer Chains Limits -To use MultiGov, your DAO must meet the following requirements: +Define the transfer restrictions for each connected network. You can adjust: -- **ERC20Votes token** - your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance -- **Flexible voting support** - your DAO's Governor must support Flexible Voting to function as the Hub Governor. If your existing Governor does not support Flexible Voting, you can upgrade it to enable this feature + - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain + - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains -## What do I need to set up MultiGov for my project? +Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. -Get started by filling out the form below: +![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) +--- END CONTENT --- -https://www.tally.xyz/get-started +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/post-deployment/ +--- BEGIN CONTENT --- +--- +title: Native Token Transfers Post Deployment +description: Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +categories: NTT, Transfer +--- -Tally will reach out to help get your DAO set up with MultiGov. +# Native Token Transfers Post Deployment -To set up testing MultiGov for your DAO, you'll need: +To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): -- [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} and [Git](https://git-scm.com/downloads){target=\_blank} installed -- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke) -- Modify and deploy the hub and spoke contracts using the provided scripts -- Set up the necessary environment variables and configurations +- Implement a robust testing plan for your multichain token before launching +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure +- Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately +- Monitor and maintain your multichain deployment -## Can MultiGov be used with non-EVM chains? +## Manual Relaying for Solana Transfers -The current implementation is designed for EVM-compatible chains. However, Solana (non-EVM) voting is currently in development and expected to go live after the EVM contracts. +By default, NTT transfers to Solana require manual relaying, meaning that after initiating a cross-chain transfer, the recipient must submit an on-chain transaction to claim the tokens. -## How can I customize voting parameters in MultiGov? +This step ensures that tokens are properly minted or unlocked on Solana and prevents unauthorized claims. -Voting parameters such as voting delay, voting period, proposal threshold, and quorum (and others) can be customized in the deployment scripts (`DeployHubContractsSepolia.s.sol` and `DeploySpokeContractsOptimismSepolia.s.sol` as examples for their respective chains). Make sure to adjust these parameters according to your DAO's specific needs before deployment. +## Where to Go Next -Remember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security. +
    -## How does MultiGov handle potential network issues or temporary chain unavailability? +- :octicons-code-16:{ .lg .middle } **Wormhole NTT Connect Demo** -MultiGov includes several mechanisms to handle network issues or temporary chain unavailability: + --- -1. **Asynchronous vote aggregation** - votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable -2. **Proposal extension** - the `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems -3. **Wormhole retry mechanism** - Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through -4. **Decentralized relayer network** - Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline + Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. -However, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios. + [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) -## How does MultiGov differ from traditional DAO governance? +- :octicons-code-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo** -Unlike traditional DAO governance, which typically operates on a single blockchain, MultiGov allows for coordinated decision-making and proposal execution across multiple chains. This enables more inclusive participation from token holders on different networks and more complex, cross-chain governance actions. + --- -## What are the main components of MultiGov? + Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework. -The main components of MultiGov include: + [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk) -- **Hub chain** - central coordination point for governance activities -- **Spoke chains** - additional chains where token holders can participate in governance -- **Wormhole integration** - enables secure cross-chain message passing -- **Governance token** - allows holders to participate in governance across all integrated chains +
    --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/get-started/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/troubleshoot/ --- BEGIN CONTENT --- --- -title: Get Started with Multigov -description: Follow this guide to set up your environment and request access to deploy MultiGov contracts for multichain DAO governance using Wormhole messaging. -categories: MultiGov +title: Troubleshooting NTT Deployment +description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +categories: NTT, Transfer --- -# Get Started with Multigov - -## Introduction +# Troubleshoot Your NTT Deployment -[MultiGov](/docs/products/multigov/overview/){target=\_blank} enables multichain governance using Wormhole messaging. With MultiGov, token holders can create proposals, vote, and execute decisions from any supported chain, eliminating the need to bridge assets or rely on a single governance hub. +If you encounter issues during the NTT deployment process, check the following common points: -This page walks you through the MultiGov deployment flow—from requesting access with Tally to choosing a network and following the appropriate deployment guide. +- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} + - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** + - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain +- **Mint authority transfer** + - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section + - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details +- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section +- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} +- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file -## Prerequisites + ???- interface "Dockerfile" -Before deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL): + ```Dockerfile + FROM ubuntu:20.04 + # Set environment variables to prevent interactive prompts during installation + ENV DEBIAN_FRONTEND=noninteractive -- **EVM chains**: - - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\_blank} standard - - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting + # Update and install necessary dependencies + RUN apt-get update && apt-get install -y \ + curl \ + wget \ + git \ + build-essential \ + libssl-dev \ + libudev-dev \ + pkg-config \ + python3 \ + python3-pip \ + software-properties-common \ + ca-certificates \ + unzip \ + clang \ + cmake \ + protobuf-compiler \ + && apt-get clean && rm -rf /var/lib/apt/lists/* -- **Solana**: - - Use an SPL token - - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\_blank} + # Install Rust + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + ENV PATH="/root/.cargo/bin:$PATH" -## Request Tally Access + # Install Solana CLI ({{ntt.solana_cli_version}}) + RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" + ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" -MultiGov integrations are coordinated through [Tally](https://www.tally.xyz/explore){target=\_blank}, a multichain governance platform that powers proposal creation, voting, and execution. + # Install Anchor using avm + RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ + && avm install 0.29.0 \ + && avm use 0.29.0 + ENV PATH="/root/.avm/bin:$PATH" -To get started, fill out the integration [intake form](https://www.tally.xyz/get-started){target=\_blank}. The Tally team will review your application and contact you to discuss deployment and setup requirements. -Once approved, review the deployment flow below to understand the integration process. Then, follow the appropriate deployment guide to integrate MultiGov with your governance token on EVM chains, Solana, or other supported networks. + ENV NVM_DIR=/root/.nvm + RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ + && . "$NVM_DIR/nvm.sh" \ + && nvm install 22 \ + && nvm use 22 \ + && nvm alias default 22 + ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" -## Deployment Flow + # Install Bun + RUN curl -fsSL https://bun.sh/install | bash + ENV PATH="/root/.bun/bin:$PATH" -MultiGov deployments follow a similar structure on both EVM and Solana. This section provides a high-level overview of the end-to-end flow. Each step is explained in more detail in the platform-specific deployment guides linked [below](#next-steps). + # Install Foundry + RUN curl -L https://foundry.paradigm.xyz | bash + ENV PATH="/root/.foundry/bin:${PATH}" + RUN /bin/bash -c "source /root/.bashrc && foundryup" -[timeline(wormhole-docs/.snippets/text/products/multigov/deployment-flow-timeline.json)] + # Install Wormhole NTT CLI + RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash -## Next Steps + # Add a default working directory + WORKDIR /app -You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: + # Expose port for development if needed + EXPOSE 8899 - - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains - - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation + # Entry point for the container + CMD ["bash"] + ``` + + ???- interface "docker-compose.yml" + ```yml + services: + portal-ntt: + build: + context: . + dockerfile: Dockerfile + platform: linux/amd64 + volumes: + - ./src:/app + working_dir: /app + tty: true + ``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ --- BEGIN CONTENT --- --- -title: Deploy MultiGov on EVM Chains -description: Set up and deploy MultiGov to EVM locally with step-by-step instructions for configuring, compiling, and deploying smart contracts across chains. -categories: MultiGov +title: Native Token Transfers Overview +description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. +categories: NTT, Transfer --- -# Deploy MultiGov on EVM Chains - -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. - -Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. - -## Prerequisites +## Native Token Transfers Overview -To interact with MultiGov, you'll need the following: +Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. -- Install [Foundry](https://book.getfoundry.sh/getting-started/installation){target=\_blank} -- Install [Git](https://git-scm.com/downloads){target=\_blank} -- Clone the repository: - ```bash - git clone https://github.com/wormhole-foundation/multigov - cd evm # for evm testing/deploying - ``` +## Key Features -## Development Setup +- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls +- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments +- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted +- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps -For developers looking to set up a local MultiGov environment: -1. Install dependencies: - ```bash - forge install - ``` +## Deployment Models -2. Set up environment variables: - ```bash - cp .env.example .env - ``` +NTT offers two operational modes for your existing tokens: - Edit `.env` with your specific [configuration](#configuration){target=\_blank} +- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts +- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token -3. Compile contracts: - ```bash - forge build - ``` +## Supported Token Standards -4. Deploy contracts (example for Sepolia testnet): +Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. - For hub chains: - ```bash - forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast - ``` +The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. - For spoke chains (e.g., Optimism Sepolia): - ```bash - forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast - ``` +NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. -## Configuration +## Deployment Process -When deploying MultiGov, several key parameters need to be set. Here are the most important configuration points: +Here's a breakdown of the key steps involved when deploying NTT: -### Hub Governor Key Parameters +- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready +- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke +- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} +- **Initialization** - specify target chains and token details, and set up your CLI environment if using it +- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees +- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles +- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed -- `initialVotingDelay` ++"uint256"++ - the delay measured in seconds before voting on a proposal begins. For example, `86400` is one day -- `initialProposalThreshold` ++"uint256"++ - the number of tokens needed to create a proposal -- `initialQuorum` ++"uint256"++ - the minimum number of votes needed for a proposal to be successful -- `initialVoteWeightWindow` ++"uint256"++ - a window where the minimum checkpointed voting weight is taken for a given address. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The voting window is measured in seconds, e.g., `86400` is one day +## Use Cases - !!! note - This helps mitigate cross-chain double voting. +- **Cross-Chain Swaps and Liquidity Aggregation** -### Hub Proposal Extender Key Parameters + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains + - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers + - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution -- `extensionDuration` ++"uint256"++ - the amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours -- `minimumExtensionDuration` ++"uint256"++ - lower time limit, in seconds, for extension duration. For example, `3600` is one hour +- **Borrowing and Lending Across Chains** -### Spoke Vote Aggregator Key Parameters + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets + - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains + - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time -- `initialVoteWindow` ++"uint256"++ - the moving window in seconds for vote weight checkpoints. These checkpoints are taken whenever an address that is delegating sends or receives tokens. For example, `86400` is one day +- **Gas Abstraction** - !!! note - This is crucial for mitigating cross-chain double voting + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments + - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains -### Hub Evm Spoke Vote Aggregator Key Parameters +- **Cross-Chain Payment Widgets** -- `maxQueryTimestampOffset` ++"uint256"++ - the max timestamp difference, in seconds, between the requested target time in the query and the current block time on the hub. For example, `1800` is 30 minutes + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens -### Updateable Governance Parameters +- **Cross-Chain Staking** -The following key parameters can be updated through governance proposals: + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks + - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains -- `votingDelay` - delay before voting starts (in seconds) -- `votingPeriod` - duration of the voting period (in seconds) -- `proposalThreshold` - threshold for creating proposals (in tokens) -- `quorum` - number of votes required for quorum -- `extensionDuration` - the amount of time for which target proposals will be extended (in seconds) -- `voteWeightWindow` - window for vote weight checkpoints (in seconds) -- `maxQueryTimestampOffset` - max timestamp difference allowed between a query's target time and the hub's block time +## Next Steps -These parameters can be queried using their respective getter functions on the applicable contract. +Follow these steps to get started with NTT: -To update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process. +[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-solana/ +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ --- BEGIN CONTENT --- --- -title: MultiGov Deployment to Solana -description: Learn how to deploy the MultiGov Staking Program on Solana, including setup, funding, deployment, and configuration steps. -categories: MultiGov +title: NTT CLI Commands +description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. +categories: NTT, Transfer --- -# Deploy MultiGov on Solana +# NTT CLI Commands -This guide provides instructions on how to set up and deploy the **MultiGov Staking Program** on Solana. Before proceeding with the deployment, ensure that MultiGov aligns with your project's governance needs by reviewing the system [architecture](/docs/products/multigov/concepts/architecture/){target=\_blank}. +## Introduction -Once your project setup is complete, follow this guide to configure, compile, and deploy the necessary Solana programs and supporting accounts. This deployment enables decentralized governance participation on Solana as a spoke chain within the MultiGov system. +The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -## Prerequisites +If you haven't installed the NTT CLI yet, follow the [NTT Installation](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank} instructions to set it up before proceeding. -To deploy MultiGov on Solana, ensure you have the following installed: +## Table of Commands - - Install [Git](https://git-scm.com/downloads){target=\_blank} - - Install [Node.js](https://nodejs.org/){target=\_blank} **`v20.10.0`** - - Install [Solana CLI](https://docs.anza.xyz/cli/install/){target=\_blank} **`v1.18.20`** - - Install [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`v0.30.1`** - - Install [Rust](https://www.rust-lang.org/tools/install){target=\_blank} **`v1.80.1`** - - Install [Docker](https://www.docker.com/get-started/){target=\_blank} - - Clone the repository: - ```bash - git clone https://github.com/wormhole-foundation/multigov.git - cd multigov/solana/ - ``` +The following table lists the available NTT CLI commands, descriptions, and examples. -## Build the Project +To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. -To create a verifiable build of the MultiGov Staking Program, run the following command: +### General Commands -```bash -./scripts/build_verifiable_staking_program.sh -``` +| Command | Description | Example | +|-----------------------------------------|--------------------------------------------------------|--------------------------------------------------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest` | +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0` | +| `ntt clone
    ` | initialize a deployment file from an existing contract | `ntt clone Mainnet Solana Sol5678...` | +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | -Once the build is complete, the compiled artifacts will be available in the `target` folder. +### Configuration Commands -## Set Up the Deployer Account +| Command | Description | Example | +|----------------------------------------------|-----------------------------------------|------------------------------------------------| +| `ntt config set-chain ` | set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key` | +| `ntt config unset-chain ` | unset a configuration value for a chain | `ntt config unset-chain Ethereum scan_api_key` | +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key` | -For a successful deployment, you need a funded deployer account on Solana. This account will store the program and execute deployment transactions. +### Solana Commands -In this section, you will create a new keypair, check the account balance, and ensure it has enough SOL tokens to cover deployment costs. If needed, you can fund the account using different methods before deploying. +| Command | Description | Example | +|------------------------------------------------|----------------------------------------------------------|-------------------------------------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json` | +| `ntt solana token-authority ` | print the token authority address for a given program ID | `ntt solana token-authority Sol1234...` | +| `ntt solana ata ` | print the token authority address for a given program ID | `ntt solana ata Mint123... Owner123... token22` | -### Generate a New Keypair +## Where to Go Next -To create a new keypair and save it to a file, run the following command: +
    -```bash -solana-keygen new --outfile ./app/keypairs/deployer.json -``` -### Check the Deployer Account Address +- :octicons-gear-16:{ .lg .middle } **Configure NTT** -To retrieve the public address of the newly created keypair, run the following command: + --- -```bash -solana address -k ./app/keypairs/deployer.json -``` + Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. -### Check the Deployer Account Balance + [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) -To verify the current balance of the deployer account, run the following command: +- :octicons-question-16:{ .lg .middle } **NTT FAQs** -```bash -solana balance -k ./app/keypairs/deployer.json -``` + --- -!!! warning - When deploying the MultiGov Staking Program, the deployer account must have enough SOL to cover deployment costs and transaction fees. + Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. - - 7.60219224 SOL for deployment costs - - 0.00542 SOL for transaction fees + [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) -### Fund the Deployer Account +
    +--- END CONTENT --- -If the account does not have enough SOL, use one of the following methods to add funds. +Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/managers-transceivers/ +--- BEGIN CONTENT --- +--- +title: Managers and Transceivers +description: Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. +categories: NTT, Transfer +--- - - **Transfer SOL from another account** - if you already have SOL in another account, transfer it using a wallet (Phantom, Solflare, etc.) or in the terminal +# Managers and Transceivers - ```bash - solana transfer --from /path/to/funder.json - ``` +## Managers - - **Request an airdrop (devnet only)** - if deploying to devnet, you can request free SOL +_Managers_ oversee the token transfer process and handle rate-limiting and message attestation. They manage interactions with multiple transceivers and ensure that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. Each NTT manager corresponds to a single token but can control multiple transceivers. Key functions include: - ```bash - solana airdrop 2 -k ./app/keypairs/deployer.json +- **`transfer`** - initiate the transfer process where tokens on the source chain are locked or burned. This process ensures that an equivalent amount of tokens can be minted or unlocked on the destination chain + + ```solidity + function transfer( + uint256 amount, // amount (in atomic units) + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes32 recipient // recipient address (Wormhole formatted) + ) external payable nonReentrant whenNotPaused returns (uint64) ``` - - **Use a Solana faucet (devnet only)** - you can use online faucets to receive 10 free SOL +- **`quoteDeliveryPrice`** - calculate the cost of sending messages across chains by querying the transceivers for estimates on message delivery fees, allowing users to know the price before initiating a transfer - - [Solana Faucet](https://faucet.solana.com/){target=\_blank} + ```solidity + function quoteDeliveryPrice( + uint16 recipientChain, // chain ID (Wormhole formatted) + bytes memory transceiverInstructions // extra instructions for transceivers (Transceiver-dependent on whether extra instructions are used/accepted) + ) public view returns (uint256[] memory, uint256) + ``` -## Deploy the MultiGov Staking Program +- **`setPeer`** - to maintain secure cross-chain communication, managers establish trust relationships between different instances of NTT manager contracts across chains. By recognizing each other as peers, they ensure that the token transfers happen securely and that rate limits on inbound transactions are respected -With the deployer account set up and funded, you can deploy the MultiGov Staking Program to the Solana blockchain. This step involves deploying the program, verifying the deployment, and ensuring the necessary storage and metadata are correctly configured. Once the IDL is initialized, the program will be ready for further setup and interaction. + ```solidity + function setPeer( + uint16 peerChainId, // chain ID (Wormhole formatted) + bytes32 peerContract, // peer NTT Manager address (Wormhole formatted) + uint8 decimals, // token decimals on the peer chain + uint256 inboundLimit // inbound rate limit (in atomic units) + ) public onlyOwner + ``` -### Deploy the Program +## Transceivers -Deploy the MultiGov Staking Program using Anchor: +_Transceivers_ are responsible for routing NTT transfers through the manager on the source chain and ensuring they are delivered to the corresponding manager on the recipient chain. They work with managers to ensure that messages are accurately processed and tokens are correctly transferred, providing a reliable system for cross-chain token transfers. Transceivers can be defined independently of the Wormhole core and modified to support any verification backend. Key functions: -```bash -anchor deploy --provider.cluster https://api.devnet.solana.com --provider.wallet ./app/keypairs/deployer.json -``` +- **`sendMessage`** - this external function sends token transfer messages to a specified recipient chain. It encodes the token transfer details into a message format recognized by the system -### Verify the Deployment + ```solidity + function sendMessage( + uint16 recipientChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction, // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + bytes memory nttManagerMessage, // serialized NTT Manager message, provided by the NTT Manager + bytes32 recipientNttManagerAddress, // NTT Manager address on the recipient chain (Wormhole formatted) + bytes32 refundAddress // address to receive refunds on the destination chain in case of excess quotes (Wormhole formatted) + ) external payable nonReentrant onlyNttManager + ``` -After deployment, check if the program is successfully deployed by running the following command: +- **`quoteDeliveryPrice`** - provides an estimation of the cost associated with delivering a message to a target chain and gauges transaction fees -```bash -solana program show INSERT_PROGRAM_ID -``` + ```solidity + function quoteDeliveryPrice( + uint16 targetChain, // chain ID (Wormhole formatted) + TransceiverStructs.TransceiverInstruction memory instruction // extra instruction for the Transceiver (optional, dependent on whether extra instructions are used/accepted for this Transceiver) + ) external view returns (uint256) + ``` -### Extend Program Storage +## Lifecycle of a Message -If the deployed program requires additional storage space for updates or functionality, extend the program storage using the following command: +### EVM -```bash -solana program extend INSERT_PROGRAM_ID 800000 -``` +#### Transfer -### Initialize the IDL +A client calls on `transfer` to initiate an NTT transfer. The client must specify, at minimum, the transfer amount, the recipient chain, and the recipient address on the recipient chain. `transfer` also supports a flag to specify whether the `NttManager` should queue rate-limited transfers or revert. Clients can also include additional instructions to forward along to the transceiver on the source chain. Depending on the mode set in the initial configuration of the `NttManager` contract, transfers are either "locked" or "burned." Once the transfer has been forwarded to the transceiver, the `NttManager` emits the `TransferSent` event. -To associate an IDL file with the deployed program, run the following command: +**Events** -```bash -anchor idl init --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json INSERT_PROGRAM_ID +```ts +/// @notice Emitted when a message is sent from the nttManager. +/// @dev Topic0 +/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// @param recipient The recipient of the message. +/// @param amount The amount transferred. +/// @param fee The amount of ether sent along with the tx to cover the delivery fee. +/// @param recipientChain The chain ID of the recipient. +/// @param msgSequence The unique sequence ID of the message. +event TransferSent( + bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence +); ``` -## Configure the Staking Program +#### Rate Limit -The final step after deploying the MultiGov Staking Program is configuring it for proper operation. This includes running a series of deployment scripts to initialize key components and set important governance parameters. These steps ensure that staking, governance, and cross-chain communication function as expected. +A transfer can be rate-limited on both the source and destination chains. If a transfer is rate-limited on the source chain and the `shouldQueue` flag is enabled, it is added to an outbound queue. The transfer can be released after the configured `_rateLimitDuration` has expired via the `completeOutboundQueuedTransfer` method. The `OutboundTransferQueued` and `OutboundTransferRateLimited` events are emitted. -### Run Deployment Scripts +If the client attempts to release the transfer from the queue before the expiry of the `rateLimitDuration`, the contract reverts with an `OutboundQueuedTransferStillQueued` error. -After deploying the program and initializing the IDL, execute the following scripts **in order** to set up the staking environment and necessary accounts. +Similarly, rate-limited transfers on the destination chain are added to an inbound queue. These transfers can be released from the queue via the `completeInboundQueuedTransfer` method, and the `InboundTransferQueued` event is emitted. -1. Initialize the MultiGov Staking Program with default settings: +If the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error. - ```bash - npx ts-node app/deploy/01_init_staking.ts - ``` +To deactivate the rate limiter, set `_rateLimitDuration` to 0 and enable the `_skipRateLimiting` field in the `NttManager` constructor. Configuring this incorrectly will throw an error. If the rate limiter is deactivated, the inbound and outbound rate limits can be set to 0. -2. Create an Account Lookup Table (ALT) to optimize transaction processing: +**Events** - ```bash - npx ts-node app/deploy/02_create_account_lookup_table.ts - ``` +```ts +/// @notice Emitted whenn an outbound transfer is queued. +/// @dev Topic0 +/// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. +/// @param queueSequence The location of the transfer in the queue. +event OutboundTransferQueued(uint64 queueSequence); +``` -3. Set up airlock accounts: +```ts +/// @notice Emitted when an outbound transfer is rate limited. +/// @dev Topic0 +/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// @param sender The initial sender of the transfer. +/// @param amount The amount to be transferred. +/// @param currentCapacity The capacity left for transfers within the 24-hour window. +event OutboundTransferRateLimited( + address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity +); +``` - ```bash - npx ts-node app/deploy/03_create_airlock.ts - ``` +```ts +/// @notice Emitted when an inbound transfer is queued +/// @dev Topic0 +/// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. +/// @param digest The digest of the message. +event InboundTransferQueued(bytes32 digest); +``` -4. Deploy a metadata collector: +#### Send - ```bash - npx ts-node app/deploy/04_create_spoke_metadata_collector.ts - ``` +Once the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage method`. The method signature is enforced by the transceiver but transceivers are free to determine their own implementation for transmitting messages. (e.g. a message routed through the Wormhole transceiver can be sent via Wormhole relaying, a custom relayer, or manually published via the core bridge). -5. Configure vote weight window lengths: +Once the message has been transmitted, the contract emits the `SendTransceiverMessage` event. - ```bash - npx ts-node app/deploy/05_initializeVoteWeightWindowLengths.ts - ``` +**Events** -6. Deploy the message executor for handling governance messages: +```ts +/// @notice Emitted when a message is sent from the transceiver. +/// @dev Topic0 +/// 0x53b3e029c5ead7bffc739118953883859d30b1aaa086e0dca4d0a1c99cd9c3f5. +/// @param recipientChain The chain ID of the recipient. +/// @param message The message. +event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message +); +``` - ```bash - npx ts-node app/deploy/06_create_message_executor.ts - ``` +#### Receive -### Set MultiGov Staking Program Key Parameters +Once a message has been emitted by a transceiver on the source chain, an off-chain process (for example, a relayer) will forward the message to the corresponding transceiver on the recipient chain. The relayer interacts with the transceiver via an entry point to receive messages. For example, the relayer will call the `receiveWormholeMessage` method on the `WormholeTransceiver` contract to execute the message. The `ReceiveRelayedMessage` event is emitted during this process. -When deploying MultiGov on Solana, several key parameters need to be set. Here are the most important configuration points: +This method should also forward the message to the `NttManager` on the destination chain. Note that the transceiver interface doesn't declare a signature for this method because receiving messages is specific to each transceiver, and a one-size-fits-all solution would be overly restrictive. - - `maxCheckpointsAccountLimit` ++"u64"++ - the maximum number of checkpoints an account can have. For example, `654998` is used in production, while `15` might be used for testing - - `hubChainId` `u16` - the chain ID of the hub network where proposals are primarily managed. For example, `10002` for Sepolia testnet - - `hubProposalMetadata` ++"[u8; 20]"++ - an array of bytes representing the address of the Hub Proposal Metadata contract on Ethereum. This is used to identify proposals from the hub - - `voteWeightWindowLength` ++"u64"++ - specifies the length of the checkpoint window in seconds in which the minimum voting weight is taken. The window ends at the vote start for a proposal and begins at the vote start minus the vote weight window. The vote weight window helps solve problems such as manipulating votes in a chain - - `votingTokenMint` ++"Pubkey"++ - the mint address of the token used for voting - - `governanceAuthority` ++"Pubkey"++ - the account's public key with the authority to govern the staking system. The `governanceAuthority` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup - - `vestingAdmin` ++"Pubkey"++ - the account's public key for managing vesting operations. The `vestingAdmin` should not be the default Pubkey, as this would indicate an uninitialized or incorrectly configured setup - - `hubDispatcher` ++"Pubkey"++ - the Solana public key derived from an Ethereum address on the hub chain that dispatches messages to the spoke chains. This is crucial for ensuring that only authorized messages from the hub are executed on the spoke ---- END CONTENT --- +The `NttManager` contract allows an M of N threshold for transceiver attestations to determine whether a message can be safely executed. For example, if the threshold requirement is 1, the message will be executed after a single transceiver delivers a valid attestation. If the threshold requirement is 2, the message will only be executed after two transceivers deliver valid attestations. When a transceiver attests to a message, the contract emits the `MessageAttestedTo` event. -Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-evm/ ---- BEGIN CONTENT --- ---- -title: Upgrading MultiGov on EVM -description: Learn the process and key considerations for upgrading MultiGov on EVM, ensuring system integrity and careful planning across cross-chain components. -categories: MultiGov ---- +NTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also acts as reentrancy protection as well. -# Upgrade MultiGov Contracts on EVM Chains +If a message has already been executed, the contract ends execution early and emits the `MessageAlreadyExecuted` event instead of reverting via an error. This mitigates the possibility of race conditions from transceivers attempting to deliver the same message when the threshold is less than the total number of available of transceivers (i.e. threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery. -MultiGov is designed to be flexible but stable. Due to the system's complexity and cross-chain nature, upgrades should be rare and carefully considered. When upgrades are necessary, they must be meticulously planned and executed to ensure system integrity and continuity. +**Events** -## Key Considerations for Upgrades +```ts +/// @notice Emitted when a relayed message is received. +/// @dev Topic0 +/// 0xf557dbbb087662f52c815f6c7ee350628a37a51eae9608ff840d996b65f87475 +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); +``` -- **`HubGovernor`**: - - Not upgradeable. A new deployment requires redeploying several components of the MultiGov system. Refer to the [Process for Major System Upgrade](#process-for-major-system-upgrade) section for more details +```ts +/// @notice Emitted when a message is received. +/// @dev Topic0 +/// 0xf6fc529540981400dc64edf649eb5e2e0eb5812a27f8c81bac2c1d317e71a5f0. +/// @param digest The digest of the message. +/// @param emitterChainId The chain ID of the emitter. +/// @param emitterAddress The address of the emitter. +/// @param sequence The sequence of the message. +event ReceivedMessage( + bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence +); +``` -- **`HubVotePool`**: - - Can be replaced by setting a new `HubVotePool` on the `HubGovernor` - - Requires re-registering all spokes on the new `HubVotePool` - - Must register the query type and implementation for vote decoding by calling `registerQueryType` on the new `HubVotePool` - - A new proposal would have to authorize the governor to use the newly created hub vote pool and will also handle registering the appropriate query decoders and registering the appropriate spoke `SpokeVoteAggregators` +```ts +/// @notice Emitted when a message has already been executed to notify client of against retries. +/// @dev Topic0 +/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. +/// @param sourceNttManager The address of the source nttManager. +/// @param msgHash The keccak-256 hash of the message. +event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); +``` -- **`SpokeMessageExecutor`**: - - Upgradeable via [UUPS](https://www.rareskills.io/post/uups-proxy){target=\_blank} proxy pattern - - Stores critical parameters in `SpokeMessageExecutorStorage` +#### Mint or Unlock -- **`HubEvmSpokeAggregateProposer`**: - - Needs redeployment if `HubGovernor` changes - - Requires re-registering all spokes after redeployment +Once a transfer has been successfully verified, the tokens can be minted (if the mode is "burning") or unlocked (if the mode is "locking") to the recipient on the destination chain. Note that the source token decimals are bounded between `0` and `TRIMMED_DECIMALS` as enforced in the wire format. The transfer amount is untrimmed (scaled-up) if the destination chain token decimals exceed `TRIMMED_DECIMALS`. Once the appropriate number of tokens have been minted or unlocked to the recipient, the `TransferRedeemed` event is emitted. -- **`HubProposalMetadata`**: - - Needs redeployment if `HubGovernor` changes, as it references `HubGovernor` as a parameter +**Events** -- **`SpokeMetadataCollector`**: - - Requires redeployment if the hub chain ID changes or if `HubProposalMetadata` changes +```ts +/// @notice Emitted when a transfer has been redeemed +/// (either minted or unlocked on the recipient chain). +/// @dev Topic0 +/// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. +/// @param digest The digest of the message. +event TransferRedeemed(bytes32 indexed digest); +``` -## Process for Major System Upgrade +### Solana -1. **New `HubGovernor` deployment**: - - Deploy the new `HubGovernor` contract -1. **Component redeployment**: - - Redeploy `HubEvmSpokeAggregateProposer` with the new `HubGovernor` address - - Redeploy `HubProposalMetadata` referencing the new `HubGovernor` - - If hub chain ID changes, redeploy `SpokeMetadataCollector` on all spoke chains -1. **`HubVotePool` update**: - - Set the new `HubVotePool` on the new `HubGovernor` - - Register all spokes on the new `HubVotePool` - - Register the query type and implementation for vote decoding (`HubEvmSpokeVoteDecoder`) -1. **Spoke re-registration**: - - Re-register all spokes on the new `HubEvmSpokeAggregateProposer` -1. **Verification and testing**: - - Conduct thorough testing of the new system setup - - Verify all cross-chain interactions are functioning correctly -1. **System transition and deprecation**: - - Create a proposal to switch the timelock to the new governor - - Communicate clearly to the community what changes were made -1. **Monitoring**: - - Implement a transition period where the new system is closely monitored - - Address any issues that arise promptly +#### Transfer -## Important Considerations +A client calls the `transfer_lock` or `transfer_burn` instruction based on whether the program is in `LOCKING` or `BURNING` mode. The program mode is set during initialization. When transferring, the client must specify the amount of the transfer, the recipient chain, the recipient address on the recipient chain, and the boolean flag `should_queue` to specify whether the transfer should be queued if it hits the outbound rate limit. If `should_queue` is set to false, the transfer reverts instead of queuing if the rate limit were to be hit. -- Always prioritize system stability, upgrades should only be performed when absolutely necessary -- Thoroughly audit all new contract implementations before proposing an upgrade -- Account for all affected components across all chains in the upgrade plan -- Provide comprehensive documentation for the community about the upgrade process and any changes in functionality -- Always test upgrades extensively on testnets before implementing in production ---- END CONTENT --- +!!! note + Using the wrong transfer instruction, i.e. `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error. -Doc-Content: https://wormhole.com/docs/products/multigov/guides/upgrade-solana/ ---- BEGIN CONTENT --- ---- -title: Upgrading MultiGov on Solana -description: Learn the process and key considerations for upgrading MultiGov on Solana, ensuring system integrity and careful planning across cross-chain components. -categories: MultiGov ---- +Depending on the mode and instruction, the following will be produced in the program logs: -# Upgrade MultiGov Contracts on Solana +```ts +Program log: Instruction: TransferLock +Program log: Instruction: TransferBurn +``` -The MultiGov Staking Program on Solana is designed to be upgradeable while maintaining stability. Upgrades introduce improvements, bug fixes, and new features but must be carefully planned and executed to prevent disruptions. +Outbound transfers are always added to an Outbox via the `insert_into_outbox` method. This method checks the transfer against the configured outbound rate limit amount to determine whether the transfer should be rate-limited. An `OutboxItem` is a Solana Account that holds details of the outbound transfer. The transfer can be released from the Outbox immediately if no rate limit is hit. The transfer can be released from the Outbox immediately unless a rate limit is hit, in which case it will only be released after the delay duration associated with the rate limit has expired. -This guide covers the key considerations and step-by-step process for upgrading the MultiGov Staking Program, including updating the program binary, Interface Description Language (IDL), and `HubProposalMetadata` while ensuring cross-chain compatibility. +#### Rate Limit -## Key Considerations for Upgrades +During the transfer process, the program checks rate limits via the `consume_or_delay` function. The Solana rate-limiting logic is equivalent to the EVM rate-limiting logic. -- **Program upgradeability** - you can upgrade the MultiGov Staking Program on Solana using the `anchor upgrade` command - - You need the program's new bytecode (`.so` file) and an updated IDL file to reflect any changes in the program's interface to complete an upgrade - - The program's authority (deployer) must execute the upgrade +If the transfer amount fits within the current capacity: -- **`HubProposalMetadata`** - can be updated without redeploying the entire program. You can do this by invoking the `updateHubProposalMetadata` instruction - - You must carefully validate updates to `HubProposalMetadata` to ensure compatibility with the existing system +- Reduce the current capacity +- Refill the inbound capacity for the destination chain +- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp, so it can be released immediately. -- **Cross-chain compatibility** - ensure any changes to the Solana program do not break compatibility with the Ethereum-based `HubGovernor` - - Test upgrades thoroughly on devnet before deploying to mainnet +If the transfer amount doesn't fit within the current capacity: -## Upgrade the MultiGov Program +- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`. +- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error -Follow these steps to upgrade the MultiGov Staking Program on Solana: +#### Send -1. **Prepare the new program binary** - build the updated program using the provided script +The caller then needs to request each transceiver to send messages via the `release_outbound` instruction. To execute this instruction, the caller needs to pass the account of the Outbox item to be released. The instruction will then verify that the transceiver is one of the specified senders for the message. Transceivers then send the messages based on the verification backend they are using. - ```bash - ./scripts/build_verifiable_staking_program.sh - ``` +For example, the Wormhole transceiver will send by calling `post_message` on the Wormhole program, so that the Wormhole Guardians can observe and verify the message. - The new program binary will be located at: +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the outbound release isn't performed. - ```bash - target/deploy/staking.so - ``` +The following will be produced in the program logs: -2. **Upgrade the program** - use the anchor upgrade command to deploy the new program binary +```ts +Program log: Instruction: ReleaseOutbound +``` - ```bash - anchor upgrade --program-id INSERT_PROGRAM_ID --provider.cluster INSERT_CLUSTER_URL INSERT_PATH_TO_PROGRAM_BINARY - ``` +#### Receive - Your completed anchor upgrade command should resemble the following: - ```bash - anchor upgrade --program-id DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY --provider.cluster https://api.devnet.solana.com ./target/deploy/staking.so - ``` +Similar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations. -3. **Update the IDL** - after upgrading the program, update the IDL to reflect any changes in the program's interface +The Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entrypoint instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approvals (VAAs) and stores it in a `VerifiedTransceiverMessage` account. - ```bash - anchor idl upgrade INSERT_PROGRAM_ID --filepath INSERT_PATH_TO_IDL_FILE - ``` +The following will be produced in the program logs: - Your completed IDL upgrade command should resemble the following: - ```bash - anchor idl upgrade --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY - ``` +```ts +Program log: Instruction: ReceiveMessage +``` -4. **Update `HubProposalMetadata`** - if `HubProposalMetadata` requires an update, run the following script to invoke the `updateHubProposalMetadata` instruction and apply the changes +`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works the same as the outbound rate limit mentioned previously. - ```bash - npx ts-node app/deploy/07_update_HubProposalMetadata.ts - ``` +The following will be produced in the program logs: + +```ts +Program log: Instruction: Redeem +``` + +#### Mint or Unlock + +The inbound transfer is released and the tokens are unlocked or minted to the recipient through either `release_inbound_mint` if the mode is `BURNING`, or `release_inbound_unlock` if the mode is `LOCKING`. Similar to transfer, using the wrong transfer instruction (such as `release_inbound_mint` for a program that is in locking mode) will result in `InvalidMode` error. + +!!! note + When `revert_on_delay` is true, the transaction will revert if the release timestamp hasn't been reached. When `revert_on_delay` is false, the transaction succeeds, but the minting/unlocking isn't performed. + +Depending on the mode and instruction, the following will be produced in the program logs: + +```ts +Program log: Instruction: ReleaseInboundMint +Program log: Instruction: ReleaseInboundUnlock +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/overview/ +Doc-Content: https://wormhole.com/docs/products/products/ --- BEGIN CONTENT --- --- -title: MultiGov Overview -description: Enable multichain governance with MultiGov. Create, vote, and execute DAO proposals securely across Wormhole supported networks. -categories: Multigov +title: Compare Wormhole's Cross-Chain Solutions +description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. +categories: Transfer, Basics --- -# MultiGov Overview +# Products -MultiGov is a multichain governance system that enables decentralized decision-making across multiple blockchain networks. Built on Wormhole messaging, it allows DAOs to manage proposals, voting, and execution from any connected chain without relying on a single hub or bridging assets. It empowers true multichain governance by aggregating voting power across chains and coordinating secure proposal execution. +Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. -## Key Features +Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. -MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: +Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. -- **Multichain governance** – token holders can vote and execute proposals from any supported chain -- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live -- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain -- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity -- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} +## Transfer Products -## How It Works +Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling -2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power -3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification -4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends -5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods - +
    -## Use Cases +::spantable:: -- **Cross-Chain Treasury Management** +| | Criteria | NTT | Token Bridge | Settlement | +|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| +| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | +| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | +| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | +| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | +| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | +| | Intent-Based Execution | :x: | :x: | :white_check_mark: | +| | Fast Settlement | :x: | :x: | :white_check_mark: | +| | Liquidity Optimization | :x: | :x: | :white_check_mark: | +| Integration Details @span | | | | | +| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | +| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
    Moderate | :green_circle: :green_circle: :white_circle:
    Moderate |:green_circle: :white_circle: :white_circle:
    Low | +| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets +::end-spantable:: -- **Coordinated Protocol Upgrades Across Chains** +
    - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains - -- **Progressive Decentralization for Multichain DAOs** +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub +
    -## Next Steps +Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. -Follow these steps to get started with MultiGov: +## Bridging UI -[timeline(wormhole-docs/.snippets/text/products/multigov/multigov-timeline.json)] +[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + +## Real-time Data + +[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. + +## Multichain Governance + +[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/multigov/tutorials/treasury-proposal/ +Doc-Content: https://wormhole.com/docs/products/queries/concepts/rpc-basics/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- -title: MultiGov Guides -description: Learn how to initiate a proposal on a hub chain, vote from spoke chains, aggregate the votes, and finally execute the proposal using Wormhole's MultiGov. -categories: MultiGov +title: Queries FAQs +description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. +categories: Queries --- -# Cross-Chain treasury management proposal - -This guide walks through the process of creating and executing a cross-chain governance proposal to mint W tokens to both the Optimism and Arbitrum treasuries. In this tutorial, we'll cover how to create a proposal on the hub chain (Ethereum Mainnet), cast votes from spoke chains (Optimism and Arbitrum), aggregate votes, and execute the proposal. +# Wormhole Queries FAQs -## Create a Proposal +## What libraries are available to handle queries? -The first step is to create a proposal on the hub chain, which in this case is Ethereum Mainnet. The proposal will contain instructions to mint 10 W tokens to the Optimism treasury and 15 ETH to the Arbitrum treasury. + - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses -In the following code snippet, we initialize the proposal with two transactions, each targeting the Hub's Message Dispatcher contract. These transactions will relay the governance actions to the respective spoke chains via Wormhole. +- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case -Key actions: +- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests -- Define the proposal targets (two transactions to the Message Dispatcher) -- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH) -- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum -- Finally, we submit the proposal to the `HubGovernor` contract +- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses -```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Prepare proposal details -address[] memory targets = new address[](2); -targets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS; -targets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS; -uint256[] memory values = new uint256[](2); -values[0] = 0; -values[1] = 0; -bytes[] memory calldatas = new bytes[](2); -// Prepare message for Optimism to mint 10 W tokens -// bytes created using abi.encodeWithSignature("mint(address,uint256)", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18) -calldatas[0] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - OPTIMISM_WORMHOLE_CHAIN_ID, - [OPTIMISM_WORMHOLE_TREASURY_ADDRESS], - [uint256(10 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -// Prepare message for Arbitrum to receive 15 ETH -calldatas[1] = abi.encodeWithSignature( - "dispatch(bytes)", - abi.encode( - ARBITRUM_WORMHOLE_CHAIN_ID, - [ARBITRUM_WORMHOLE_TREASURY_ADDRESS], - [uint256(15 ether)], - [hex"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000"] - ) -); -string memory description = "Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole"; -// Create the proposal -uint256 proposalId = governor.propose( - targets, values, calldatas, description -) -``` +!!! note + A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. -??? interface "Parameters" +## Are there any query examples? - `GOVERNOR_ADDRESS` ++"address"++ +Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - The address of the `HubGovernor` contract on Ethereum Mainnet. +- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} +- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} +- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} +- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} - --- +## What is the format of the response signature? - `targets` ++"address[]"++ +The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: - An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`. +```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` - --- +See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. - `values` ++"uint256[]"++ +!!! note + If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. - An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred. +## Can anyone run a query proxy server? - --- +Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. - `calldatas` ++"bytes[]"++ +It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. - The calldata for the proposal. These are encoded contract calls containing cross-chain dispatch instructions for minting tokens and sending ETH. The calldata specifies minting 10 W tokens to the Optimism treasury and sending 15 ETH to the Arbitrum treasury. +## What Does Queries Offer over an RPC Service - --- +Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. +--- END CONTENT --- - `description` ++"string"++ +Doc-Content: https://wormhole.com/docs/products/queries/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started with Queries +description: Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. +categories: Queries +--- - A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum. +# Get Started with Queries -??? interface "Returns" +## Introduction - `proposalId` ++"uint256"++ +[Queries](/docs/products/queries/overview) lets you fetch on-chain data from supported blockchains using `eth_call`-style requests without submitting transactions or paying gas. The Guardian network signs the result, making it verifiable and suitable for use on-chain. - The ID of the newly created proposal on the hub chain. +This guide walks you through requesting an API key, constructing your first query using the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, and decoding the result. -## Vote on the Proposal via Spoke +## Prerequisites -Once the proposal is created on the hub chain, stakeholders can cast their votes on the spoke chains. This snippet demonstrates how to connect to a spoke chain and cast a vote for the proposal. The voting power (weight) is calculated based on each stakeholder's token holdings on the spoke chain. +Before you begin, make sure you have the following: -Key actions: + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - A basic understanding of JavaScript or TypeScript + - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia) + - A Wormhole Queries API key -- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain -- Cast a vote in support of the proposal +## Request an API Key -```solidity -// Connect to the SpokeVoteAggregator contract of the desired chain -SpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS); -// Cast a vote -uint8 support = 1; // 1 for supporting, 0 for opposing -uint256 weight = voteAggregator.castVote(proposalId, support); -``` +Wormhole Queries is in closed beta, but you can start building today. -??? interface "Parameters" +To interact with the system, you will use the Query Proxy. This hosted service receives your query, routes it to the appropriate chain, and returns a signed, verifiable response from the Guardian network. The Query Proxy allows you to fetch on-chain data without infrastructure overhead. - `VOTE_AGGREGATOR_ADDRESS` ++"address"++ +To request access, join the beta by filling out the [access form](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. Once approved, you will receive an API key via email. - The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum). +## Construct a Query and Decode the Response - --- +Using the Wormhole Query Proxy, you will write a lightweight script to query a token contract's `name()` on Ethereum Sepolia. The response is signed by the Guardian network and locally decoded for use in your application. - `proposalId` ++"uint256"++ +1. Create a new directory for your script and initialize a Node.js project: - The ID of the proposal created on the hub chain, which is being voted on. + ```bash + mkdir queries + cd queries + npm init -y + ``` - --- +2. Add the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, [Axios](https://www.npmjs.com/package/axios){target=\_blank}, [Web3](https://www.npmjs.com/package/web3){target=\_blank}, and helper tools: - `support` ++"uint8"++ + ```bash + npm install axios web3 @wormhole-foundation/wormhole-query-sdk + npm install -D tsx typescript + ``` - The vote being cast (`1` for supporting the proposal, `0` for opposing). +3. Add a new `query.ts` script where you will write and run your query logic: -??? interface "Returns" + ```bash + touch query.ts + ``` - `weight` ++"uint256"++ +4. Paste the following script into `query.ts` to build and submit a query to the token contract's `name()` function on Ethereum Sepolia, then decode the Guardian-signed response: - The weight of the vote, determined by the voter’s token holdings on the spoke chain. + ```typescript + // Import the SDK types and helpers for making the query +import { + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; +import * as eth from 'web3'; -## Vote Aggregation +// Define the endpoint and query parameters +const query_url = 'https://testnet.query.wormhole.com/v1/query'; +const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public'; +const chain_id = 10002; // Sepolia (Wormhole chain ID) +const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract +const data = '0x06fdde03'; // function selector for `name()` -In the background process, votes cast on the spoke chains are aggregated and sent back to the hub chain for final tallying. This is typically handled off-chain by a "crank turner" service, which periodically queries the vote status and updates the hub chain. +// Load your API key from environment variables +const apiKey = process.env.API_KEY; +if (!apiKey) throw new Error('API_KEY is not set in your environment'); -Key actions: +(async () => { + // Fetch the latest block number (required to anchor the query) + const latestBlock = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; -- Aggregate votes from different chains and submit them to the hub chain for tallying + // Build the query targeting the token contract's name() function + const request = new QueryRequest(1, [ + new PerChainQueryRequest( + chain_id, + new EthCallQueryRequest(latestBlock, [{ to: token, data: data }]) + ), + ]); + const serialized = request.serialize(); -```solidity -// Aggregate votes sent to Hub (this would typically be done by a "crank turner" off-chain) -hubVotePool.crossChainVote(queryResponseRaw, signatures); -``` + // Send the query to the Wormhole Query Proxy + const response = await axios.post( + query_url, + { bytes: Buffer.from(serialized).toString('hex') }, + { headers: { 'X-API-Key': apiKey } } + ); -??? interface "Parameters" + // Decode the response returned by the Guardian network + const queryResponse = QueryResponse.from(response.data.bytes); + const chainResponse = queryResponse.responses[0] + .response as EthCallQueryResponse; + const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]); - `queryResponseRaw` ++"bytes"++ + // Output the results + console.log('\n\nParsed chain response:'); + console.log(chainResponse); + console.log('\nToken name:', name); +})(); + ``` - The raw vote data from the spoke chains. +5. Use your API key to execute the script: - --- + ```bash + API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts + ``` - `signatures` ++"bytes"++ +The expected output should be similar to this: - Cryptographic signatures that verify the validity of the votes from the spoke chains. +
    +API_KEY=123_456_789 npx tsx query.ts +Parsed chain response: +EthCallQueryResponse { +blockNumber: 8193548n, +blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8', +blockTime: 1745595132000000n, +results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000'] +} + +Token name: USDC + +
    -## Execute Proposal and Dispatch Cross-Chain Messages +## Next Steps -After the proposal passes and the votes are tallied, the next step is to execute the proposal. The `HubGovernor` contract will dispatch the cross-chain messages to the spoke chains, where the respective treasuries will receive the tokens. +Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: -Key actions: + - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM + - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually + - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts -- Execute the proposal after the voting period ends and the proposal passes -- The `execute` function finalizes the proposal execution by dispatching the cross-chain governance actions. The `descriptionHash` ensures that the executed proposal matches the one that was voted on. +Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. +--- END CONTENT --- -```solidity -HubGovernor governor = HubGovernor(GOVERNOR_ADDRESS); -// Standard timelock execution -governor.execute(targets, values, calldatas, descriptionHash); -``` +Doc-Content: https://wormhole.com/docs/products/queries/guides/construct-a-query/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- -??? interface "Parameters" +Doc-Content: https://wormhole.com/docs/products/queries/guides/mock-a-query/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - `governor` ++"HubGovernor"++ +Doc-Content: https://wormhole.com/docs/products/queries/guides/query-request/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - The `HubGovernor` contract instance. +Doc-Content: https://wormhole.com/docs/products/queries/guides/submit-response/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - --- +Doc-Content: https://wormhole.com/docs/products/queries/guides/verify-response/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - `targets` ++"address[]"++ +Doc-Content: https://wormhole.com/docs/products/queries/overview/ +--- BEGIN CONTENT --- +--- +title: Queries Overview +description: Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. +categories: Queries +--- - An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both). +# Queries Overview - --- +Queries provide on-demand access to Guardian-attested on-chain data. They allow smart contracts to fetch real-time, verifiable data from across the multichain ecosystem, such as prices, rates, and liquidity. - `values` ++"uint256[]"++ +## Key Features - An array of values (in Wei) associated with each transaction (both are zero in this case). +- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time +- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation +- **Cross-chain ready** – request data on one chain, use it on another +- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts +- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} - --- +## How It Works - `calldatas` ++"bytes[]"++ +A query request follows a simple but robust lifecycle. The off-chain service responsible for handling requests is called the CCQ Server (Cross-Chain Query Server), also referred to as the Query Server throughout this documentation. - The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH). +1. An off-chain app sends a query to the CCQ Server via HTTPS +2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} +3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} independently fetch the data, verify it, and sign the result +4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response +5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data - --- +The CCQ Server is permissioned but trustless. Most queries resolve in under one second, and Guardians retry failed requests for up to one minute. Up to 255 queries can be batched together to optimize performance, supporting efficient multichain workflows. - `descriptionHash` ++"bytes32"++ +![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp) - A hash of the proposal’s description, used to verify the proposal before execution. - -??? interface "Returns" - - No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains. - -Once the proposal is executed, the encoded messages will be dispatched via Wormhole to the spoke chains, where the Optimism and Arbitrum treasuries will receive their respective funds. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Architecture -description: Explore Wormhole's Native Token Transfers architecture, which covers components, message flow, rate limiting, and custom transceivers. -categories: NTT, Transfer ---- - -## Introduction - -The Native Token Transfers (NTT) architecture within the Wormhole ecosystem offers a robust framework for secure and efficient token transfers across multiple blockchains. This architecture relies on the manager and transceiver core components that work together to manage cross-chain communication and token operations complexities. - - -## System Components - -The NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers. - -### Managers - -_Managers_ are responsible for handling the flow of token transfers between different blockchains and ensuring that tokens are locked or burned on the source chain before being minted or unlocked on the destination chain. The main tasks of managers include rate-limiting transactions, verifying message authenticity (message attestation), and managing the interaction between multiple transceivers, who are responsible for cross-chain communications. - -Each manager is assigned to a specific token but can operate across multiple chains. Their key responsibility is to ensure that tokens are securely locked or burned on the source chain before being minted or unlocked on the destination chain. This provides the integrity of token transfers and prevents double-spending. - -A manager is responsible for: - -- **Handling token transfer flow** - upon a transfer request, `NttManager` either locks or burns tokens depending on the configuration, emits a `TransferSent` event, and ensures tokens can’t be accessed on the source chain before leasing them on the destination chain. This process safeguards against double-spending and maintains a secure transfer -- **Rate-limiting** - the `NttManager` contract includes rate-limiting functionality to prevent overloading the network or flooding the target chain. The `NttManager` applies rate limits to manage transfer flow and prevent network congestion. Limits apply to both outgoing and incoming transfers - - **Outbound** - transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted - - **Inbound** - similar limits apply on the destination chain, delaying transfers if capacity is exceeded - - Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit - -- **Message authenticity verification** - the `NttManager` ensures transfer security by verifying message authenticity through multiple attestations from transceivers. For each transfer, a threshold number of attestation signatures must be gathered from transceivers. Once verified, `NttManager` releases tokens on the destination chain, ensuring only authenticated transfers are processed -- **Interaction with transceivers** - `NttManager` collaborates with transceivers, forwarding transfer messages between chains and handling message verification. Transceivers route messages with transfer details to the destination chain, coordinating with `NttManager` to verify that tokens are locked or burned before releasing them on the other side. Transceivers can be customized to work with different security protocols, adding flexibility +## Use Cases -### Transceivers +Queries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them. -_Transceivers_ facilitate cross-chain token transfers by ensuring the accurate transmission of messages between different blockchains. They work in conjunction with managers to route token transfers from the source chain to the recipient chain. Their primary function is to ensure that messages regarding the transfer process are delivered correctly, and that tokens are safely transferred across chains. +- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** -While transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability allows them to be integrated with various verification backends to accommodate different security needs or platform-specific requirements. + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets -Transceivers are entrusted with several responsibilities: +- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** -- **Message transmission** - transceivers handle the routing of transfer messages between chains. When a transfer is initiated, the transceiver sends the message (including transfer details like recipient and amount) to the destination chain’s manager for verification and processing -- **Manager coordination** - transceivers work with managers to ensure tokens are locked or burned on the source chain before issuance on the destination chain, reinforcing the security of each transfer -- **Custom verification support** - transceivers can integrate with custom verification backends, allowing flexibility to adapt to different security protocols or chain requirements. This customization enables protocols to use different attestation standards as needed + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution + - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens -How it works: +- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** -1. The transceiver receives instructions from the manager to send messages across chains -2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred -3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades -![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp) +- **Multichain Prediction Markets** -!!! note - [Learn more](/docs/products/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\_blank} about the architecture of Native Token Transfers message lifecycles. + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution -#### Custom Transceivers +- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** -The NTT framework supports advanced features such as custom transceivers for specialized message verification, enhancing security and adaptability. The architecture includes detailed processes for initiating transfers, managing rate limits, and finalizing token operations, with specific instructions and events outlined for EVM-compatible chains and Solana. + - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks -NTT has the flexibility to support custom message verification in addition to Wormhole Guardian message verification. Custom verifiers are implemented as transceiver contracts and can be protocol-specific or provided by other third-party attesters. Protocols can also configure the threshold of attestations required to mark a token transfer as valid — for example, 2/2, 2/3, 3/5. +## Next Steps -![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp) +Follow these steps to get started with Queries: -The verifier performs checks based on predefined criteria and issues approval for transactions that meet these requirements. This approval is incorporated into the Wormhole message, ensuring that only transactions verified by both the Wormhole Guardian Network and the additional verifier are processed. The model includes an extra verifier in the bridging process, enhancing security and providing an added assurance of transaction integrity. +[timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] +--- END CONTENT --- -For more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors. +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ +--- BEGIN CONTENT --- +--- +title: Queries Supported Methods +description: Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. +categories: Queries +--- -## Lifecycle of a Message +# Supported Methods -The lifecycle of a message in the Wormhole ecosystem for Native Token Transfers (NTT) involves multiple steps to ensure secure and accurate cross-chain token transfers. This lifecycle can vary depending on the blockchain being used, and the following explanations focus on the EVM and Solana implementations. The key stages include initiating the transfer, handling rate limits, sending and receiving messages, and finally, minting or unlocking tokens on the destination chain. +Wormhole Queries provides on-demand access to [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}-attested on-chain data through a simple REST endpoint. It offers a faster, gasless alternative to traditional transaction-based data retrieval, removing the need for gas fees and transaction finality delays. Requests are handled off-chain and processed by the Guardians, delivering verified data efficiently and cost-effectively. -### Transfer +This page describes Wormhole Queries, their functionality, and available methods, aiming to assist new developers in utilizing the service. -The process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in Solana, the client uses either the `transfer_lock` or `transfer_burn` instruction, depending on whether the program is in locking or burning mode. The client specifies the transfer amount, recipient chain ID, recipient address, and a flag (`should_queue` on both EVM and Solana) to decide whether the transfer should be queued if it hits the rate limit. +## Supported Query Types -In both cases: +Wormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains. -- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain -- If the source chain is in burning mode, the tokens are burned on the source chain, and new tokens are minted on the destination chain +!!! note + For a more comprehensive technical description and further specifics on each query type, please consult the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md). -Once initiated, an event (such as `TransferSent` on EVM or a corresponding log on Solana) is emitted to signal that the transfer process has started. -### Rate Limit +### eth_call -Both EVM and Solana implement rate-limiting for transfers to prevent abuse or network overload. Rate limits apply to both the source and destination chains. If transfers exceed the current capacity, depending on whether the `shouldQueue` flag is set to true, they can be queued. +The [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} query type allows you to perform read-only calls to a smart contract on a specific block, identified by its number or hash. Some of eth_call's configurations include: -- On EVM, the transfer is added to an outbound queue if it hits the rate limit, with a delay corresponding to the configured rate limit duration. If `shouldQueue` is set to false, the transfer is reverted with an error -- On Solana, the transfer is added to an **Outbox** via the `insert_into_outbox method`, and if the rate limit is hit, the transfer is queued with a `release_timestamp`. If `shouldQueue` is false, the transfer is reverted with a `TransferExceedsRateLimit` error +- **Batching** - group multiple calls, even to different contracts, into a single query targeting the same block, which is processed as one batch RPC call to simplify on-chain verification +- **Capacity** - batch up to 255 individual in a single eth_call query +- **Result data** - provides the specified block's number, hash, timestamp, and the output from the contract call -Both chains emit events or logs when transfers are rate-limited or queued. +### eth_call_by_timestamp -### Send +The [`eth_call_by_timestamp`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#timestamp-and-block-id-hints-in-eth_call_by_timestamp){target=\_blank} query is similar to a standard `eth_call` but targets a specific timestamp instead of a block ID. This is useful for retrieving on-chain data based on a precise point in time, especially for correlating information across different chains. -After being forwarded to the Transceiver, the message is transmitted across the chain. Transceivers are responsible for delivering the message containing the token transfer details. Depending on the Transceiver's implementation, messages may be routed through different systems, such as Wormhole relayers or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission. +The query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block. -- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use Wormhole relayers or custom relaying solutions to forward the message -- In Solana, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The Solana transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification +### eth_call_with_finality -In both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on Solana) is emitted to signal that the message has been transmitted. +The [`eth_call_with_finality`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#desired-finality-in-eth_call_with_finality){target=\_blank} query type functions like a standard `eth_call`, but with an added critical assurance: it will only return the query results once the specified block has reached a designated level of finality on its chain. -### Receive +You can specify one of two finality levels for your query: -Upon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. +- **Finalized** - indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain +- **Safe** - refers to a block considered highly unlikely to be reorganized, offering a substantial degree of confidence, though the network's consensus may not fully finalize it -- In EVM, the message is received by the `NttManager` on the destination chain, which verifies the message's authenticity. Depending on the M of N threshold set for the attestation process, the message may require attestations from multiple transceivers -- In Solana, the message is received via the `receive_message` instruction in the Wormhole Transceiver program. The message is verified and stored in a `VerifiedTransceiverMessage` account, after which it is placed in an Inbox for further processing +!!! note + If the target blockchain does not natively support or recognize the safe finality tag, requesting safe finality will be treated as a request for finalized finality instead. -In both chains, replay protection mechanisms ensure that a message cannot be executed more than once. Events or logs are emitted (e.g., `ReceivedMessage` on EVM or `ReceiveMessage` on Solana) to notify that the message has been successfully received. +### sol_account -### Mint or Unlock +The [`sol_account`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana-queries){target=\_blank} query reads on-chain data for one or more specified accounts on the Solana blockchain. This functionality is similar to using Solana's native [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} RPC method, enabling you to retrieve information for multiple accounts simultaneously -Finally, after the message is verified and attested to, the tokens can be either minted (if they were burned on the source chain) or unlocked (if they were locked). The tokens are then transferred to the recipient on the destination chain, completing the cross-chain token transfer process. +### sol_pda -- On EVM, tokens are either minted (if burned on the source chain) or unlocked (if locked on the source chain). The `TransferRedeemed` event signals that the tokens have been successfully transferred -- On Solana, the tokens are unlocked or minted depending on whether the program is in locking or burning mode. The `release_inbound_unlock` or `release_inbound_mint` instruction is used to complete the transfer, and a corresponding log is produced +The [`sol_pda`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana_queries){target=\_blank} query reads data for one or more Solana [Program Derived Addresses](https://www.anchor-lang.com/docs/pdas){target=\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data. -In both cases, once the tokens have been released, the transfer process is complete, and the recipient receives the tokens. Events are emitted to indicate that the transfer has been fully redeemed. +This is particularly useful for accessing multiple PDAs owned by a specific program or for verifying Solana PDA derivations on another blockchain, such as how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/concepts/security/ +Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-networks/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Security -description: Explore the security measures of Native Token Transfers, including the Global Accountant and governance strategies for seamless token safety. -categories: NTT, Transfer +title: Queries Supported Networks +description: Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. +categories: Queries --- -# Security - -## Global Accountant - -The Global Accountant is a defense-in-depth security feature that checks the integrity of every token transfer. It ensures that chain balances remain isolated and more tokens cannot be burned and transferred out of a chain than were ever minted. +# Supported Networks -This feature ensures native asset fungibility remains in 1:1 parity. At no time will assets coming from a spoke chain exceed the number of native assets sent to that spoke chain. The Guardians, with their role in enforcing accounting transparency, provide a reassuring layer of security, attesting to a Native Token Transfer (NTT) only if it passes integrity checks. +This page provides a quick reference for chains supported by Wormhole Queries, including each chain's Wormhole chain ID and the level of support for key methods: [`eth_call`](/docs/products/queries/reference/supported-methods/#eth_call){target=\_blank}, [`eth_call_by_timestamp`](/docs/products/queries/reference/supported-methods/#eth_call_by_timestamp){target=\_blank}, and [`eth_call_with_finality`](/docs/products/queries/reference/supported-methods/#eth_call_with_finality){target=\_blank}. -[Contact](https://discord.com/invite/wormholecrypto){target=\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment. +The **Expected History** column shows how much recent state data is typically available for querying, though this can vary depending on the chain and the configuration of each Guardian node. -## Governance and Upgradeability +The support shown in the table reflects what has been confirmed through testing. However, query success ultimately depends on whether the underlying call can be executed on each Guardian’s RPC node. -Integrators should implement governance mechanisms to manage the addition and removal of transceivers and to upgrade contracts using proxy patterns, as demonstrated in the upgrade functions in the `NttManager` contracts. These processes can also set thresholds and rules for attestation and message approval. +For example, many chains use a fork of [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which by default retains 128 blocks of state in memory (unless archive mode is enabled). On Ethereum mainnet, this covers around 25 minutes of history—but on faster chains like Optimism, it may span only about three minutes. While Guardian nodes are expected to have access to recent state, there are currently no guarantees on how far back historical data is available. -The registry component of the NTT system is crucial for maintaining a trusted list of transceivers and managing their status. Governance processes for the following actions can be submitted directly to the corresponding contract on-chain, whether it is one or multiple of the bridging contracts or one of the token contracts: +## Mainnet -- Adding or removing a transceiver address from the registry -- Setting the token contract address on a bridging contract -- Setting the Wormhole Core Contract address on a bridging contract -- Setting the registered bridging contract address on the token contract +| Chain | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History | +|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:| +| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | +| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | +| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | +| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | +| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | +| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | +| Karura | 11 | ✅ | ✅ | ✅ | archive | +| Acala | 12 | ✅ | ✅ | ✅ | archive | +| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | +| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks | +| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks | +| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | +| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | +| Base | 30 | ✅ | ✅ | ✅ | archive | -This governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed. +ℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/access-control/ +Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ --- BEGIN CONTENT --- --- -title: Native Token Transfers Access Control -description: Learn about the owner and pauser access roles for the NTT manager contract, which can be used to pause and un-pause token transfers. -categories: NTT, Transfer +title: Chain IDs +description: This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. +categories: Reference --- -## Owner and Pauser Roles - -Pausing the Native Toke Transfer (NTT) Manager Contract will disallow initiating new token transfers. While the contract is paused, in-flight transfers can still be redeemed (subject to rate limits if configured). - -NTT can be paused on a particular chain by updating the `paused` parameter on the deployment to `true` via the NTT CLI, then performing `ntt push` to sync the local configuration with the on-chain deployment. - -- **Owner** - full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused -- **Pauser** - can pause NTT contracts to halt token transfers temporarily. This role is crucial for responding quickly to adverse events without a prolonged governance process. Cannot un-pause contracts - -You may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory. +# Chain IDs -```json -{ - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": true, // set to true to pause the contract - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - //... - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } -} -``` +The following table documents the chain IDs used by Wormhole and places them alongside the more commonly referenced [EVM Chain IDs](https://chainlist.org/){target=\_blank}. !!! note - While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`. - -The `Owner` and the `Pauser` addresses can each pause the contract. Since the contract `Owner` address is typically a multisig or a more complex DAO governance contract, and pausing the contract only affects the availability of token transfers, protocols can choose to set the `Pauser` address to be a different address. Creating a separate `Pauser` helps protocols respond quickly to potential risks without going through a drawn-out process. - -Consider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/configuration/rate-limiting/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Rate Limiting -description: Learn about rate limits in Wormhole NTT by configuring send/receive limits, queuing, and canceling flows to manage multichain token transfers efficiently. -categories: NTT, Transfer ---- - -## Introduction - -The Native Token Transfer (NTT) framework provides configurable per-chain rate limits for sending and receiving token transfers. Integrators can manage these limits via their own governance processes to quickly adapt to on-chain activity. + Please note, Wormhole chain IDs are different than the more commonly referenced EVM [chain IDs](https://eips.ethereum.org/EIPS/eip-155){target=\_blank}, specified in the Mainnet and Testnet ID columns. -If a transfer is rate-limited on the source chain and queueing is enabled via `shouldQueue = true`, the transfer is placed into an outbound queue and can be released after the rate limit expires. + + -You can configure the following limits on every chain where NTT is deployed directly using the manager: +=== "Mainnet" -- **Sending limit** - a single outbound limit for sending tokens from the chain -- **Per-chain receiving limits** - the maximum receiving limit, which can be configured on a per-chain basis. For example, allowing 100 tokens to be received from Ethereum but only 50 tokens to be received from Arbitrum - -Rate limits are replenished every second over a fixed duration. While the default duration is 24 hours, the value is configurable at contract creation. Rate-limited transfers on the destination chain are added to an inbound queue with a similar release delay. - -## Update Rate Limits - -To configure or update the sending and receiving rate limits, follow these steps: - -1. **Locate the deployment file** - open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts - -2. **Modify the limits section** - for each chain, locate the limits field and update the outbound and inbound values as needed - - ```json - "limits": { - "outbound": "1000.000000000000000000", - "inbound": { - "Ethereum": "100.000000000000000000", - "Arbitrum": "50.000000000000000000" - } - } - ``` - - - **`outbound`** - sets the maximum tokens allowed to leave the chain - - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific chains - -3. **Push the configuration** - use the NTT CLI to synchronize the updated configuration with the blockchain - - ```bash - ntt push - ``` - -4. **Verify the changes** - after pushing, confirm the new rate limits by checking the deployment status - - ```bash - ntt status - ``` - -???- note "`deployment.json` example" - ```json - { - "network": "Testnet", - "chains": { - "Sepolia": { - "version": "1.1.0", - "mode": "burning", - "paused": false, - "owner": "0x0088DFAC40029f266e0FF62B82E47A07467A0345", - "manager": "0x5592809cf5352a882Ad5E9d435C6B7355B716357", - "token": "0x5CF5D6f366eEa7123BeECec1B7c44B2493569995", - "transceivers": { - "threshold": 1, - "wormhole": { - "address": "0x91D4E9629545129D427Fd416860696a9659AD6a1", - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - }, - "limits": { - "outbound": "184467440737.095516150000000000", - "inbound": { - "ArbitrumSepolia": "500.000000000000000000" - } - }, - "pauser": "0x0088DFAC40029f266e0FF62B82E47A07467A0345" - } - } - } - ``` + | Ethereum | 2 | 1 | +| Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | +| Acala | 12 | 787 | +| Algorand | 8 | mainnet-v1.0 | +| Aptos | 22 | 1 | +| Arbitrum | 23 | Arbitrum One-42161 | +| Avalanche | 6 | C-Chain-43114 | +| Base | 30 | Base-8453 | +| Berachain | 39 | | +| Blast | 36 | 81457 | +| BNB Smart Chain | 4 | 56 | +| Celestia | 4004 | celestia | +| Celo | 14 | 42220 | +| Cosmos Hub | 4000 | cosmoshub-4 | +| Dymension | 4007 | dymension_1100-1 | +| Evmos | 4001 | evmos_9001-2 | +| Fantom | 10 | 250 | +| Gnosis | 25 | 100 | +| HyperEVM | 47 | | +| Injective | 19 | injective-1 | +| Ink | 46 | | +| Kaia | 13 | 8217 | +| Karura | 11 | 686 | +| Kujira | 4002 | kaiyo-1 | +| Linea | 38 | 59144 | +| Mantle | 35 | 5000 | +| Mezo | 50 | | +| Monad | 48 | | +| Moonbeam | 16 | 1284 | +| NEAR | 15 | mainnet | +| Neon | 17 | 245022934 | +| Neutron | 4003 | neutron-1 | +| Noble | 4009 | noble-1 | +| Oasis | 7 | 42262 | +| Optimism | 24 | 10 | +| Osmosis | 20 | osmosis-1 | +| Polygon | 5 | 137 | +| Provenance | 4008 | pio-mainnet-1 | +| Pythnet | 26 | | +| Scroll | 34 | 534352 | +| SEDA | 4006 | | +| Sei | 32 | pacific-1 | +| Seievm | 40 | | +| SNAXchain | 43 | 2192 | +| Sonic | 52 | 146 | +| Stargaze | 4005 | stargaze-1 | +| Sui | 21 | 35834a8a | +| Terra | 3 | columbus-5 | +| Terra 2.0 | 18 | phoenix-1 | +| Unichain | 44 | | +| World Chain | 45 | 480 | +| X Layer | 37 | 196 | +| XPLA | 28 | dimension_37-1 | -## Queuing Mechanism +=== "Testnet" -When a transfer exceeds the rate limit, it is held in a queue and can be released after the set rate limit duration has expired. The sending and receiving queuing behavior is as follows: + | Ethereum Holesky | 10006 | Holesky-17000 | +| Ethereum Sepolia | 10002 | Sepolia-11155111 | +| Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | +| Acala | 12 | 597 | +| Algorand | 8 | testnet-v1.0 | +| Aptos | 22 | 2 | +| Arbitrum Sepolia | 10003 | Sepolia-421614 | +| Avalanche | 6 | Fuji-43113 | +| Base Sepolia | 10004 | Base Sepolia-84532 | +| Berachain | 39 | 80084 | +| Blast | 36 | 168587773 | +| BNB Smart Chain | 4 | 97 | +| Celestia | 4004 | mocha-4 | +| Celo | 14 | Alfajores-44787 | +| Cosmos Hub | 4000 | theta-testnet-001 | +| Dymension | 4007 | | +| Evmos | 4001 | evmos_9000-4 | +| Fantom | 10 | 4002 | +| Gnosis | 25 | Chiado-10200 | +| HyperEVM | 47 | 998 | +| Injective | 19 | injective-888 | +| Ink | 46 | 763373 | +| Kaia | 13 | Kairos-1001 | +| Karura | 11 | 596 | +| Kujira | 4002 | harpoon-4 | +| Linea | 38 | 59141 | +| Mantle | 35 | Sepolia-5003 | +| Mezo | 50 | 31611 | +| Monad | 48 | 10143 | +| Moonbeam | 16 | Moonbase-Alphanet-1287 | +| NEAR | 15 | testnet | +| Neon | 17 | 245022940 | +| Neutron | 4003 | pion-1 | +| Noble | 4009 | grand-1 | +| Oasis | 7 | 42261 | +| Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | +| Osmosis | 20 | osmo-test-5 | +| Polygon Amoy | 10007 | Amoy-80002 | +| Provenance | 4008 | | +| Pythnet | 26 | | +| Scroll | 34 | Sepolia-534351 | +| SEDA | 4006 | seda-1-testnet | +| Sei | 32 | atlantic-2 | +| Seievm | 40 | | +| SNAXchain | 43 | 13001 | +| Sonic | 52 | 57054 | +| Stargaze | 4005 | | +| Sui | 21 | 4c78adac | +| Terra | 3 | bombay-12 | +| Terra 2.0 | 18 | pisco-1 | +| Unichain | 44 | Unichain Sepolia-1301 | +| World Chain | 45 | 4801 | +| X Layer | 37 | 195 | +| XPLA | 28 | cube_47-5 | + +--- END CONTENT --- -- **Sending** - if an outbound transfer violates rate limits, users can either revert and try again later or queue their transfer. Users must return after the queue duration has expired to complete sending their transfer -- **Receiving** - if an inbound transfer violates rate limits, it is in a queue. Users or relayers must return after the queue duration has expired to complete receiving their transfer on the destination chain +Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ +--- BEGIN CONTENT --- +--- +title: Wormhole Finality | Consistency Levels +description: This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. +categories: Reference +--- -Queuing is configured dynamically during each transfer by passing the `shouldQueue` parameter to the [`transfer` function](https://github.com/wormhole-foundation/native-token-transfers/blob/5e7ceaef9a5e7eaa13e823a67c611dc684cc0c1d/evm/src/NttManager/NttManager.sol#L171-L182){target=\_blank} in the `NttManager` contract. +# Wormhole Finality -## Cancel Flows +The following table documents each chain's `consistencyLevel` values (i.e., finality reached before signing). The consistency level defines how long the Guardians should wait before signing a VAA. The finalization time depends on the specific chain's consensus mechanism. The consistency level is a `u8`, so any single byte may be used. However, a small subset has particular meanings. If the `consistencyLevel` isn't one of those specific values, the `Otherwise` column describes how it's interpreted. -If users bridge frequently between a given source chain and destination chain, the capacity could be exhausted quickly. Loss of capacity can leave other users rate-limited, potentially delaying their transfers. The outbound transfer cancels the inbound rate limit on the source chain to avoid unintentional delays. This allows for refilling the inbound rate limit by an amount equal to the outbound transfer amount and vice-versa, with the inbound transfer canceling the outbound rate limit on the destination chain and refilling the outbound rate limit with an amount. + + +| Ethereum | 200 | 201 | | finalized | ~ 19min | Details | +| Solana | | 0 | 1 | | ~ 14s | Details | +| Acala | 200 | 201 | | finalized | ~ 24s | | +| Algorand | | | 0 | | ~ 4s | Details | +| Aptos | | | 0 | | ~ 4s | Details | +| Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | +| Avalanche | 200 | | | finalized | ~ 2s | Details | +| Base | 200 | 201 | | finalized | ~ 18min | | +| Berachain | 200 | | | finalized | ~ 4s | | +| Blast | 200 | 201 | | finalized | ~ 18min | | +| BNB Smart Chain | 200 | 201 | | finalized | ~ 48s | Details | +| Celestia | | | 0 | | ~ 5s | | +| Celo | 200 | | | finalized | ~ 10s | | +| Cosmos Hub | | | 0 | | ~ 5s | | +| Dymension | | | 0 | | ~ 5s | | +| Evmos | | | 0 | | ~ 2s | | +| Fantom | 200 | | | finalized | ~ 5s | | +| Injective | | | 0 | | ~ 3s | | +| Ink | | | 0 | | ~ 9min | | +| Kaia | 200 | | | finalized | ~ 1s | | +| Karura | 200 | 201 | | finalized | ~ 24s | Details | +| Kujira | | | 0 | | ~ 3s | | +| Mantle | 200 | 201 | | finalized | ~ 18min | | +| Mezo | | | 0 | | ~ 8s | | +| Monad | | | 0 | | ~ 2s | | +| Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | +| NEAR | | | 0 | | ~ 2s | Details | +| Neutron | | | 0 | | ~ 5s | | +| Oasis | 200 | | | finalized | ~ 12s | | +| Optimism | 200 | 201 | | finalized | ~ 18min | | +| Osmosis | | | 0 | | ~ 6s | | +| Polygon | 200 | | | finalized | ~ 66s | Details | +| Scroll | 200 | | | finalized | ~ 16min | | +| Sei | | | 0 | | ~ 1s | | +| Sonic | | | 0 | | ~ 1s | | +| Stargaze | | | 0 | | ~ 5s | | +| Sui | | | 0 | | ~ 3s | Details | +| Terra | | | 0 | | ~ 6s | | +| Terra 2.0 | | | 0 | | ~ 6s | | +| Unichain | 200 | 201 | | finalized | ~ 18min | | +| World Chain | | | 0 | | ~ 18min | | +| X Layer | 200 | 201 | | finalized | ~ 16min | | +| XPLA | | | 0 | | ~ 5s | | + --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/faqs/ +Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ --- BEGIN CONTENT --- --- -title: Native Token Transfers FAQs -description: Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. -categories: NTT, Transfer +title: Contract Addresses +description: This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. +categories: Reference --- -# Wormhole NTT FAQs +# Contract Addresses -## Do you have an example of how cross-chain lending can be implemented using Wormhole? +## Core Contracts -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. + + -Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. +=== "Mainnet" -## What causes the "No protocols registered for Evm" error in Wormhole SDK? - -This error typically occurs when the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} cannot recognize or register the necessary EVM protocols, which are required for interacting with Ethereum-based networks. The most common reason for this error is that the relevant EVM package for Wormhole's NTT has not been imported correctly. - -To resolve this issue, ensure you have imported the appropriate Wormhole SDK package for EVM environments. The necessary package for handling NTT on EVM chains is `@wormhole-foundation/sdk-evm-ntt`. Here's the correct import statement: - -```rust -import '@wormhole-foundation/sdk-evm-ntt'; -``` - -By importing this package, the Wormhole SDK can register and utilize the required protocols for EVM chains, enabling cross-chain token transfers using the NTT framework. Ensure to include this import at the start of your code, especially before attempting any interactions with EVM chains in your project. - -## How can I transfer ownership of NTT to a multisig? + | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | +| Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | +| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Algorand | 842125965 | +| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | +| Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | +| Avalanche | 0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c | +| Base | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Berachain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| Blast | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| BNB Smart Chain | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | +| Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | +| Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | +| NEAR | contract.wormhole_crypto.near | +| Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | +| Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | +| Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | +| Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | +| Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | +| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | +| Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | +| Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | +| World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | +| X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | -Transferring ownership of Wormhole's NTT to a multisig is a two-step process for safety. This ensures that ownership is not transferred to an address that cannot claim it. Refer to the `transfer_ownership` method in the [NTT Manager Contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/example-native-token-transfers/src/instructions/admin/transfer_ownership.rs#L55){target=\_blank} to initiate the transfer. +=== "Testnet" -1. **Initiate transfer** - use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig) -2. **Claim ownership** - the multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer -3. **Single-step transfer (Riskier)** - you can also use the `transfer_ownership_one_step_unchecked` method to transfer ownership in a single step, but if the new owner cannot sign, the contract may become locked. Be cautious and ensure the new owner is a Program Derived Address (PDA) + | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | +| Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | +| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | +| Algorand | 86525623 | +| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | +| Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | +| Avalanche | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | +| Base Sepolia | 0x79A1027a6A159502049F10906D333EC57E95F083 | +| Berachain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Blast | 0x473e002D7add6fB67a4964F13bFd61280Ca46886 | +| BNB Smart Chain | 0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D | +| Celo | 0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56 | +| Fantom | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | +| Gnosis | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| HyperEVM | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | +| Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | +| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | +| Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | +| Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | +| Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | +| Monad | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Moonbeam | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | +| NEAR | wormhole.wormhole.testnet | +| Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | +| Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | +| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | +| Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | +| Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | +| Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | +| Pythnet | EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z | +| Scroll | 0x055F47F1250012C6B20c436570a76e52c17Af2D5 | +| Sei | sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s | +| Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | +| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | +| Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | +| Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | +| World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | +| X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | +| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | -For a practical demonstration of transferring ownership of Wormhole's NTT to a multisig on Solana, visit the [GitHub demo](https://github.com/wormhole-foundation/demo-ntt-solana-multisig-tools){target=\_blank} providing scripts and guidance for managing an NTT program using Squads multisig functionality, including ownership transfer procedures. +=== "Devnet" -## How can I specify a custom RPC for NTT? + | Ethereum | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | +| Solana | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | +| Algorand | 1004 | +| Aptos | 0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017 | +| BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | +| NEAR | wormhole.test.near | +| Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | +| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | +| Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | + -To specify a custom RPC for Wormhole's NTT, create an `overrides.json` file in the root of your deployment directory. This file allows you to define custom RPC endpoints, which can be helpful when you need to connect to specific nodes or networks for better performance, security, or control over the RPC connection. +## Token Bridge -Below’s an example of how the `overrides.json` file should be structured: + + -???- code "`overrides.json`" - ```json - { - "chains": { - "Bsc": { - "rpc": "http://127.0.0.1:8545" - }, - "Sepolia": { - "rpc": "http://127.0.0.1:8546" - }, - "Solana": { - "rpc": "http://127.0.0.1:8899" - } - } - } - ``` +=== "Mainnet" -## How can I redeem tokens if NTT rate limits block them on the target chain? + | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | +| Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | +| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | +| Algorand | 842126029 | +| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | +| Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | +| Avalanche | 0x0e082F06FF657D94310cB8cE8B0D9a04541d8052 | +| Base | 0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627 | +| Berachain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| Blast | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| BNB Smart Chain | 0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7 | +| Celo | 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed | +| Fantom | 0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2 | +| Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | +| Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | +| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | +| Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | +| NEAR | contract.portalbridge.near | +| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | +| Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | +| Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | +| Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | +| Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | +| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | +| Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | +| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | +| Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | +| Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | +| World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | +| X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | +| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | -If the rate limits on Wormhole's NTT block tokens from being received on the target chain, the transaction will typically be paused until the rate limits are adjusted. Rate limits are implemented to manage congestion and prevent chain abuse, but they can occasionally delay token redemptions. +=== "Testnet" -To resolve this: + | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | +| Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | +| Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | +| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | +| Algorand | 86525641 | +| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | +| Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Avalanche | 0x61E44E506Ca5659E6c0bba9b678586fA2d729756 | +| Base Sepolia | 0x86F55A04690fd7815A3D802bD587e83eA888B239 | +| Berachain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Blast | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | +| BNB Smart Chain | 0x9dcF9D205C9De35334D646BeE44b2D2859712A09 | +| Celo | 0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153 | +| Fantom | 0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8 | +| HyperEVM | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | +| Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | +| Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | +| Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | +| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | +| Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | +| Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | +| Monad | 0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659 | +| Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | +| NEAR | token.wormhole.testnet | +| Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | +| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | +| Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | +| Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | +| Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | +| Sei | sei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2 | +| Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | +| SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | +| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | +| Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | +| Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | +| World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | +| X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | +| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | -1. **Adjust rate limits** - the rate limits must be modified by an administrator or through the appropriate configuration tools to allow the blocked transaction to proceed -2. **Resume transaction flow** - once the rate limits are adjusted, you can resume the flow, which should be visible in the UI. The tokens will then be redeemable on the target chain +=== "Devnet" -In most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process. + | Ethereum | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | +| Solana | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | +| Algorand | 1006 | +| Aptos | 0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31 | +| BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | +| NEAR | token.test.near | +| Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | +| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | +| Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | + -## What are the challenges of deploying NTT to non-EVM chains? +## Wormhole Relayer -NTT requires the same transceiver for all routes, limiting flexibility when deploying across EVM and non-EVM chains. For example, if you're deploying to Ethereum, Arbitrum, and Solana, you can't use Wormhole and Axelar as transceivers because Axelar doesn't support Solana. This constraint forces integrators to use a single transceiver (e.g., Wormhole) for all chains, reducing flexibility in optimizing cross-chain transfers. + + -## Does the NTT manager function as an escrow account for a hub chain? +=== "Mainnet" -Yes, the NTT manager acts like an escrow account for non-transferable tokens on a hub chain. To manage non-transferable tokens, you would add the NTT manager to the allowlist, ensuring that only the NTT manager can hold and control the tokens as they are transferred across chains. + | Ethereum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Arbitrum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Avalanche | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Base | 0x706f82e9bb5b0813501714ab5974216704980e31 | +| Berachain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Blast | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| BNB Smart Chain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Celo | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Fantom | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Ink | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Kaia | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Mantle | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Moonbeam | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | +| X Layer | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -## Which functions or events does Connect rely on for NTT integration? +=== "Testnet" -Connect relies on the NTT SDK for integration, with platform-specific implementations for both [Solana](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/ts/sdk/ntt.ts){target=\_blank} and [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/ts/src/ntt.ts){target=\_blank}. The key methods involved include: - -- **Initiate and redeem functions** - these functions are essential for initiating token transfers and redeeming them on the destination chain -- **Rate capacity methods** - methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion - -These functions ensure Connect can handle token transfers and manage chain-rate limits. - -## How does the relayer contract determine which transceiver to call? - -The source chain's transceiver includes the destination chain's transceiver in the message via the relayer contract. The admin configures each transceiver's mapping of its peers on other chains. This mapping allows the destination transceiver to verify that the message came from a trusted source. + | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | +| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | +| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | +| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | +| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | +| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | +| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -## How do I create a verifier or transceiver? +=== "Devnet" -To run your verifier, you need to implement a transceiver. This involves approximately 200 lines of code, leveraging the base functionality provided by the [abstract transceiver contract](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\_blank}. + | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | +| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | + -For reference, you can review the [Axelar transceiver implementation](https://github.com/wormhole-foundation/example-wormhole-axelar-wsteth/blob/main/src/axelar/AxelarTransceiver.sol){target=\_blank}. +## CCTP -## Can I use Hetzner for the NTT deployment? + + -No, using Hetzner servers for Solana deployments is not recommended. Hetzner has blocked Solana network activity on its servers, leading to connection issues. Hetzner nodes will return a `ConnectionRefused: Unable to connect` error for Solana deployments. Therefore, choosing alternative hosting providers that support Solana deployments is advisable to ensure seamless operation. +=== "Mainnet" -## How can I transfer tokens with NTT with an additional payload? + | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | +| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | +| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | +| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | -You can include an extra payload in NTT messages by overriding specific methods in the [NttManager contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\_blank}. +=== "Testnet" -- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L216-L226){target=\_blank} to query any additional data you need for the transfer. The extra payload can then be added to the message -- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol#L262-L275){target=\_blank} to process and utilize the extra payload sent in the message + | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | +| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | +| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -!!!Important - You cannot pass the additional data as part of the entry point directly. Instead, the data must be queried on-chain via the `_handleMsg` method, ensuring the payload is properly included and processed. +=== "Devnet" -## Why use NTT over xERC20? + N/A + + -Shortcomings of xERC20: +## Settlement Token Router -- **Single point of failure** - xERC20 relies on multiple bridges, but a compromise in any single bridge can jeopardize the token. It enforces a 1-of-n design rather than a more robust m-of-n approach -- **No pausing** - xERC20 lacks mechanisms to pause operations during emergencies -- **No access control** - there are no built-in access controls for managing token transfers securely -- **Limited rate limiting** - rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security -- **No integration with relaying systems** - xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups +=== "Mainnet" -While xERC20 is an extension of the ERC20 standard, NTT is designed as a framework rather than a rigid standard. It is compatible with any token that supports `burn` and `mint` functions and allows the NTT manager to act as a minter. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | + | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | -## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet? +=== "Testnet" -To begin transferring tokens to a chain in burning mode when no tokens are locked, you must first send tokens to the NTT manager to back the supply. The address of the NTT manager can be found in the `deployment.json` file. + | Chain Name | Contract Address | + |----------------------|-------------------------------------------------| + | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | + | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | + | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + -## Is there a way to use NTT tokens with chains that don't currently support NTT? +## Read-Only Deployments -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +=== "Mainnet" -- **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) -- **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism -- **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT + | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | +| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | +| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. +!!!note + Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/get-started/ +Doc-Content: https://wormhole.com/docs/products/reference/glossary/ --- BEGIN CONTENT --- --- -title: Get Started with NTT -description: NTT enables cross-chain token movement without wrapping. Install the CLI, deploy test tokens, and scaffold a project to integrate NTT into your app. -categories: NTT, Transfer +title: Glossary +description: Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. +categories: Basics --- -# Get Started with NTT - -## Introduction - -The [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview){target=\_blank} framework enables seamless cross-chain token movement without wrapping or liquidity pools. This guide shows you how to install the NTT CLI, which is used to configure and deploy native token contracts, and scaffold your first project for deployment on testnet or mainnet. - -If you are looking for a no-code experience to deploy on mainnet, you can explore the [NTT Launchpad](https://ntt.wormhole.com){target=\_blank}. +# Glossary -## Prerequisites +This glossary is an index of technical term definitions for words commonly used in Wormhole documentation. -Before you begin, make sure you have: +## Chain ID -- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} -- [Bun installed](https://bun.sh/){target=\_blank} -- A wallet private key with tokens on supported chains -- ERC-20 or SPL tokens already deployed on the source and destination chains +Wormhole assigns a unique `u16` integer chain ID to each supported blockchain. These chain IDs are specific to Wormhole and may differ from those used by blockchains to identify their networks. -## Don’t Have a Token Yet? +You can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} page. -To use NTT, you must have a token already deployed on the source and destination chains. If you don’t have one, follow the quick guides below to deploy a basic test token. +## Consistency Level -???- interface "Deploy an ERC-20 Token on EVM" - Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} to deploy a basic ERC-20 token contract on testnet. +The level of finality (consistency) a transaction should meet before being signed by a Guardian. See the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page for details. - 1. **Install Foundry** - install the [Forge CLI](https://book.getfoundry.sh/getting-started/installation){target=\_blank} +## Delivery Provider - 2. **Clone the repository** – fetch the example contract repository +A Delivery Provider monitors for Wormhole Relayer delivery requests and delivers those requests to the intended target chain as instructed. - ```bash - git clone https://github.com/wormhole-foundation/example-ntt-token.git - cd example-ntt-token - ``` - - 3. **Deploy the token contract** – deploy to testnet with your preferred name, symbol, minter, and owner addresses +## Emitter - ```bash - forge create --broadcast \ - --rpc-url INSERT_RPC_URL \ - --private-key INSERT_YOUR_PRIVATE_KEY \ - src/PeerToken.sol:PeerToken \ - --constructor-args "INSERT_TOKEN_NAME" "INSERT_TOKEN_SYMBOL" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS - ``` +The emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address and, a sequence number for the message is tracked to provide a unique ID. - 4. **Mint tokens** – send tokens to your address +## Finality - ```bash - cast send INSERT_TOKEN_ADDRESS \ - "mint(address,uint256)" \ - INSERT_RECIPIENT_ADDRESS \ - INSERT_AMOUNT_IN_WEI \ - --private-key INSERT_YOUR_PRIVATE_KEY \ - --rpc-url INSERT_RPC_URL - ``` +The finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused won't be reverted. - !!! note - This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18). +## Guardian +A [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig. -???- interface "Create and Mint SPL Tokens" - This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. +## Guardian Network - 1. **Generate a Solana key pair** - run the following command to create a new wallet: +Validators in their own P2P network who serve as Wormhole's oracle by observing activity on-chain and generating signed messages attesting to that activity. - ```bash - solana-keygen grind --starts-with w:1 --ignore-case - ``` +## Guardian Set - 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: +The Guardian Set is a set of guardians responsible for validating a message emitted from the core contracts. Occasionally, the members of the set will change through a governance action. - ```bash - solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON - ``` +## Heartbeat - 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: +Each Guardian will issue a `heartbeat` on a 15-second interval to signal that it is still running and convey details about its identity, uptime, version, and the status of the connected nodes. - === "Mainnet" - ```bash - solana config set -um - ``` +You can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - === "Testnet" - ```bash - solana config set -ut - ``` +## Observation - === "Devnet" - ```bash - solana config set -ud - ``` +An Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node. - 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: +## Relayer - ```bash - solana airdrop 2 - solana balance - ``` +A relayer is any process that delivers VAAs to a destination. - 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} +## Sequence - ```bash - cargo install spl-token-cli - ``` +A nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address. - 6. **Create a new SPL token** - initialize the token on Solana +## Spy - ```bash - spl-token create-token - ``` +A Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed. - 7. **Create a token account** - generate an account to hold the token +## VAA - ```bash - spl-token create-account INSERT_TOKEN_ADDRESS - ``` +[Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs) are the base data structure in the Wormhole ecosystem. They contain emitted messages along with information such as what contract emitted the message. - 8. **Mint tokens** - send 1000 tokens to the created account +## Validator - ```bash - spl-token mint INSERT_TOKEN_ADDRESS 1000 - ``` +A daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts. +--- END CONTENT --- - !!! note - NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. +Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ +--- BEGIN CONTENT --- +--- +title: Supported Networks +description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. +categories: Reference +--- -## Install NTT CLI +# Supported Networks -The NTT CLI is recommended to deploy and manage your cross-chain token configuration. +Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -1. Run the installation command in your terminal: +## Networks - ```bash - curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash - ``` + + +
    -2. Verify the NTT CLI is installed: +### Connect - ```bash - ntt --version - ``` - -## Initialize a New NTT Project - -1. Once the CLI is installed, scaffold a new project by running: - - ```bash - ntt new my-ntt-project - cd my-ntt-project - ``` +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    + + +
    -2. Initialize a new `deployment.json` file specifying the network: +### NTT - === "Mainnet" - ```bash - ntt init Mainnet - ``` +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    + + +
    - === "Testnet" - ```bash - ntt init Testnet - ``` +### Token Bridge - After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network. +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    + + +
    - === "Mainnet" - ```json - { - "network": "Mainnet", - "chains": {} - } - ``` +### CCTP - === "Testnet" - ```json - { - "network": "Testnet", - "chains": {} - } - ``` +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    + + +
    -In the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings. +### Settlement -## Next Steps +| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    + + +
    -You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: +### MultiGov -- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | +| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | +| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ +Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ --- BEGIN CONTENT --- --- -title: Native Token Transfers EVM Deployment -description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer +title: Testnet Faucets +description: This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. +categories: Reference --- -# Native Token Transfers (NTT) EVM Development +# Testnet Faucets -## Deploy Your Token and Ensure Compatibility +## Get Started -If you still need to do so, deploy the token contract to the destination or spoke chains. +Don't let the need for testnet tokens get in the way of buildling your next great idea with Wormhole. Use this guide to quickly locate the testnet token faucets you need to deploy and test applications and contracts on Wormhole's supported networks. -### Requirements for Token Deployment + + +
    -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +### EVM -#### Burn-and-Mint Mode +| Ethereum Holesky | EVM | ETH | Alchemy Faucet | +| Ethereum Sepolia | EVM | ETH | Alchemy Faucet | +| Acala | EVM | ACA | Discord Faucet | +| Arbitrum Sepolia | EVM | ETH | List of Faucets | +| Avalanche | EVM | AVAX | Official Avalanche Faucet | +| Base Sepolia | EVM | ETH | List of Faucets | +| Berachain | EVM | BERA | Official Berachain Faucet | +| Blast | EVM | ETH | List of Faucets | +| BNB Smart Chain | EVM | BNB | Official BNB Faucet | +| Celo | EVM | CELO | Official Celo Faucet | +| Fantom | EVM | FTM | Official Fantom Faucet | +| Gnosis | EVM | xDAI | Official Gnosis Faucet | +| HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | +| Ink | EVM | ETH | Official Ink Faucet | +| Kaia | EVM | KAIA | Official Kaia Faucet | +| Karura | EVM | ACA | Discord Faucet | +| Linea | EVM | ETH | List of Faucets | +| Mantle | EVM | MNT | Official Mantle Faucet | +| Monad | EVM | MON | Official Monad Faucet | +| Moonbeam | EVM | DEV | Official Moonbeam Faucet | +| Neon | EVM | NEON | Official Neon Faucet | +| Oasis | EVM | TEST | Official Oasis Faucet | +| Optimism Sepolia | EVM | ETH | Superchain Faucet | +| Polygon Amoy | EVM | POL | Official Polygon Faucet | +| Scroll | EVM | ETH | List of Faucets | +| Unichain | EVM | ETH | QuickNode Faucet | +| World Chain | EVM | ETH | Alchemy Faucet | +| X Layer | EVM | OKB | X Layer Official Faucet | -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: +### SVM -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` +| Pythnet | SVM | ETH | Superchain Faucet | -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. +### AVM -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; +| Algorand | AVM | ALGO | Official Algorand Faucet | -interface INttToken { - /// @notice Error when the caller is not the minter. - /// @dev Selector 0x5fb5729e. - /// @param caller The caller of the function. - error CallerNotMinter(address caller); +### CosmWasm - /// @notice Error when the minter is the zero address. - /// @dev Selector 0x04a208c7. - error InvalidMinterZeroAddress(); +| Celestia | CosmWasm | TIA | Discord Faucet | +| Cosmos Hub | CosmWasm | ATOM | Discord Faucet | +| Evmos | CosmWasm | TEVMOS | Official Evmos Faucet | +| Injective | CosmWasm | INJ | Official Injective Faucet | +| Kujira | CosmWasm | KUJI | Discord Faucet | +| Neutron | CosmWasm | NTRN | List of Faucets | +| Noble | CosmWasm | USDC | Circle Faucet | +| Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | +| SEDA | CosmWasm | SEDA | Official SEDA Faucet | +| Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | +| Terra | CosmWasm | LUNA | Terra Official Faucet | +| Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | +| XPLA | CosmWasm | XPLA | XPLA Official Faucet | - /// @notice Error when insufficient balance to burn the amount. - /// @dev Selector 0xcf479181. - /// @param balance The balance of the account. - /// @param amount The amount to burn. - error InsufficientBalance(uint256 balance, uint256 amount); +### Move VM - /// @notice The minter has been changed. - /// @dev Topic0 - /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. - /// @param newMinter The new minter. - event NewMinter(address previousMinter, address newMinter); +| Aptos | Move VM | APT | Official Aptos Faucet | - // NOTE: the `mint` method is not present in the standard ERC20 interface. - function mint(address account, uint256 amount) external; +### NEAR VM - // NOTE: the `setMinter` method is not present in the standard ERC20 interface. - function setMinter(address newMinter) external; +| NEAR | NEAR VM | NEAR | Official NEAR Faucet | - // NOTE: NttTokens in `burn` mode require the `burn` method to be present. - // This method is not present in the standard ERC20 interface, but is - // found in the `ERC20Burnable` interface. - function burn(uint256 amount) external; -} - ``` +### Sui Move VM -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. +| Sui | Sui Move VM | SUI | List of Faucets | +
    + +--- END CONTENT --- -#### Hub-and-Spoke Mode +Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ +--- BEGIN CONTENT --- +--- +title: Wormhole Formatted Addresses +description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. +categories: Reference +--- -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. +# Wormhole Formatted Addresses - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers +## Introduction -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. +This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. +## Platform-Specific Address Formats -For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. +Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. -### Key Differences Between Modes +Here’s an overview of the native address formats and how they are normalized to the Wormhole format: - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +| Platform | Native Address Format | Wormhole Formatted Address | +|-----------------|----------------------------------|----------------------------| +| EVM | Hex (e.g., 0x...) | 32-byte Hex | +| Solana | Base58 | 32-byte Hex | +| CosmWasm | Bech32 | 32-byte Hex | +| Algorand | Algorand App ID | 32-byte Hex | +| Sui | Hex | 32-byte Hex | +| Aptos | Hex | 32-byte Hex | +| Near | SHA-256 | 32-byte Hex | -## Deploy NTT +These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. -Create a new NTT project: +### Address Format Handling -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment +The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + +```typescript +const platformAddressFormatEntries = [ + ['Evm', 'hex'], + ['Solana', 'base58'], + ['Cosmwasm', 'bech32'], + ['Algorand', 'algorandAppId'], + ['Sui', 'hex'], + ['Aptos', 'hex'], + ['Near', 'sha256'], +]; ``` -Initialize a new `deployment.json` file specifying the network: +These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. -=== "Testnet" +## Universal Address Methods - ```bash - ntt init Testnet - ``` +The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. -=== "Mainnet" +Key functions: - ```bash - ntt init Mainnet + - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + + ```typescript + const universalAddress = new UniversalAddress('0x123...', 'hex'); ``` -Ensure you have set up your environment correctly: + - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address -```bash -export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY -``` + ```typescript + const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); + const universalAddress = ethAddress.toUniversalAddress().toString(); + ``` -Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia: + - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform -```bash -# Set scanner API Keys as environment variables -export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY -export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY + ```typescript + const nativeAddress = universalAddress.toNative('Evm'); + ``` -# Add each chain -# The contracts will be automatically verified using the scanner API keys above -ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS -``` + - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations -While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification. + ```typescript + console.log(universalAddress.toString()); + ``` -The `ntt add-chain` command takes the following parameters: +These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. -- Name of each chain -- Version of NTT to deploy (use `--latest` for the latest contract versions) -- Mode (either `burning` or `locking`) -- Your token contract address +## Convert Between Native and Wormhole Formatted Addresses -The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood. +The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. -## Configure NTT +### Convert a Native Address to a Wormhole Formatted Address -The NTT CLI takes inspiration from [git](https://git-scm.com/){target=\_blank}. You can run: +Example conversions for EVM and Solana: -- `ntt status` - checks whether your `deployment.json` file is consistent with what is on-chain -- `ntt pull` - syncs your `deployment.json` file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example: +=== "EVM" - For Solana, the limits are set with 9 decimal places: - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - } - ``` + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; - For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places: - ```json - "inbound": { - "Solana": "1000.000000000000000000" // inbound limit from Solana to Sepolia - } - ``` +const ethAddress: NativeAddress<'Evm'> = toNative( + 'Ethereum', + '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' +); +const universalAddress = ethAddress.toUniversalAddress().toString(); +console.log('Universal Address (EVM):', universalAddress); + ``` - This initial configuration ensures that the rate limits are correctly represented for each chain's token precision - -- `ntt push` - syncs the on-chain configuration with local changes made to your `deployment.json` file +=== "Solana" -After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running `ntt status` and following the instructions shown on the screen. + ```typescript + import { toNative } from '@wormhole-foundation/sdk-core'; -## Set Token Minter to NTT Manager +const solAddress: NativeAddress<'Solana'> = toNative( + 'Solana', + '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' +); +const universalAddressSol = solAddress.toUniversalAddress().toString(); +console.log('Universal Address (Solana):', universalAddressSol); + ``` -The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in `burning` mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain. +The result is a standardized address format that is ready for cross-chain operations. -!!! note - The required NTT Manager address can be found in the `deployment.json` file. +### Convert Back to Native Addresses -- If you followed the [`INttToken`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} interface, you can execute the `setMinter(address newMinter)` function - ```json - cast send $TOKEN_ADDRESS "setMinter(address)" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL - ``` +Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: -- If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter +```typescript +const nativeAddressEvm = universalAddress.toNative('Evm'); +console.log('EVM Native Address:', nativeAddressEvm); -By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. +const nativeAddressSolana = universalAddress.toNative('Solana'); +console.log('Solana Native Address:', nativeAddressSolana); +``` -!!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. ---- END CONTENT --- +These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Solana Deployment -description: Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. -categories: NTT, Transfer ---- +## Use Cases for Wormhole Formatted Addresses -# Deploy Native Token Transfers on Solana +### Cross-chain Token Transfers -[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. +Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. +### Smart Contract Interactions -The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. +In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. -![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) +### DApp Development -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. +For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +### Relayers and Infrastructure -## Prerequisites +Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. +--- END CONTENT --- -Before deploying NTT on Solana, ensure you have the following: +Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ +--- BEGIN CONTENT --- +--- +title: Settlement Protocol Architecture +description: Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. +categories: Settlement, Transfer +--- -- [Rust](https://www.rust-lang.org/tools/install){target=\_blank} -- [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** -- [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** +# Settlement Protocol Architecture -Use the Solana and Anchor versions listed above to avoid compatibility issues while following this guide. +## Introduction -## Overview of the Deployment Process +This page describes the high-level mechanics of the underlying native swap protocols in the Wormhole SDK. While built on Wormhole messaging, each protocol uses a novel architecture with unique price discovery, scalability, and latency tradeoffs. These designs enable redundancy to handle highly asymmetric flows and sharp volume changes. These sections will cover the following: -Deploying NTT with the CLI on Solana follows a structured process: +- **Wormhole Liquidity Layer** - a cross-chain transfer protocol that utilizes Solana as the central orchestration layer for cross-chain intents, allowing solvers to deploy liquidity from a single Solana-based hub rather than distributing it across each supported chain +- **Mayan Swift** - a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent +- **Mayan MCTP** - a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains -1. **Choose your token setup**: +## Wormhole Liquidity Layer - - **Use an existing SPL token** - if your token is already deployed on Solana, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section - - **Create a new SPL token** - if you don't already have an SPL token deployed, you'll need to deploy and configure it on Solana before integrating with Wormhole's NTT +Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster-than-finality transfers across the Wormhole ecosystem through a novel, Solana-based hub-and-spoke architecture. The hub-and-spoke model leverages interoperable token standards like Circle's CCTP (and Wormhole's NTT), allowing the solver to natively mint and burn assets between chains for intent fulfillment. This architecture allows solvers to facilitate cross-chain transfers by fronting assets on the destination chain and assuming the finality risk of the originating source chain transaction. - ???- interface "Create and Mint SPL Tokens" - This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens. +Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. - 1. **Generate a Solana key pair** - run the following command to create a new wallet: +![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) - ```bash - solana-keygen grind --starts-with w:1 --ignore-case - ``` +The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. - 2. **Set Solana configuration** - configure the Solana CLI to use the generated key pair using the following command: +### Solvers and Liquidity Fragmentation - ```bash - solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON - ``` +Traditional intent-based protocols require solvers to distribute their capital across each supported chain in the network. This liquidity fragmentation leads to capital inefficiency and requires complex rebalancing to manage asymmetric flows between chains. As the number of chains increases, solvers face scalability challenges, which can result in market concentration, reducing competition and potentially impacting price discovery in intent execution. - 3. **Select an RPC URL** - configure Solana to use the appropriate network using one of the following commands: +Using a hub-and-spoke model, the Wormhole Liquidity Layer solves these challenges by consolidating solver liquidity on a single chain, Solana. This model eliminates the need for complex cross-chain rebalancing and simplifies solvers' infrastructure requirements. Solvers only need to consider the finality risk of the originating source chain transaction and the payload size when bidding on transfers. By concentrating liquidity on Solana, the protocol can handle large transfer volumes with a smaller capital base, enhancing capital efficiency and lowering barriers to entry for solvers. This approach promotes competition, improves overall market efficiency, and ultimately benefits users with better prices while still preserving the speed of transactions. - === "Mainnet" - ```bash - solana config set -um - ``` +### Enable Unified Liquidity - === "Testnet" - ```bash - solana config set -ut - ``` +The novel hub-and-spoke liquidity architecture relies on interoperable token standards that enable cross-chain token fungibility, such as Circle's Cross-Chain Transfer Protocol (CCTP) and Wormhole's Native Token Transfers (NTT). These protocols allow assets to move seamlessly between chains, making unified liquidity possible. On the liquidity hub (Solana), solvers concentrate their liquidity in NTT or CCTP-supported assets, such as USDC. These assets act as the shuttle between chains but may not necessarily be the user's original or final asset. - === "Devnet" - ```bash - solana config set -ud - ``` +After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. - 4. **Fund your wallet** - ensure you have enough SOL to create a token. If deploying on devnet, request an airdrop with the following commands: +By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. - ```bash - solana airdrop 2 - solana balance - ``` +### Protocol Flow: How It Works - 5. **Install SPL Token CLI** - install or update the required [CLI tool](https://spl.solana.com/token){target=\_blank} +1. **Initiation** - users or protocols initiate a transfer via an interface or directly on-chain. They choose between a standard transfer (waiting for finality on the sending chain) or a fast transfer (triggering the auction process). For fast transfers, users or the protocol specify a maximum fee and an auction start deadline - ```bash - cargo install spl-token-cli - ``` + !!! Note + If an auction doesn't start within the set deadline, a standard transfer will proceed directly from the source to the destination chain. - 6. **Create a new SPL token** - initialize the token on Solana +2. **Auction** - solvers monitor the Wormhole network for these fast transfer requests and initiate an auction on Solana by offering to fulfill the transfer at or below the user's maximum fee. To start the auction, the solver must transfer the requested funds plus a small security deposit to the Matching Engine contract +3. **Competition** - once initiated, other solvers can participate by submitting lower bids in a simple English auction, aiming to provide users with the best rate. If a new solver submits a better offer, the previous solver's funds and security deposit are returned, with the latest offer taking precedence atomically. This competition ensures that users receive the best possible transfer rate +4. **Fulfillment** - after the auction concludes, the winning solver must complete the transfer within a predefined grace period to earn their fee and reclaim their security deposit. Failure to do so may result in the security deposit being slashed, with the slashed amount compensating the user for delays. This mechanism incentivizes prompt execution. Upon successful completion, the Fast Transfer hub sends the USDC to the user's destination wallet, and the solver receives their security deposit and transfer fee +5. **Settlement** - once the source chain transaction reaches finality, the winning solver can use the finalized Wormhole message to settle the auction with the matching engine and rebalance. This allows the solver to retrieve the original transfer amount into their wallet - ```bash - spl-token create-token - ``` +## Mayan Swift - 7. **Create a token account** - generate an account to hold the token +Mayan Swift is a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent. - ```bash - spl-token create-account INSERT_TOKEN_ADDRESS - ``` +### On-Chain Competitive Price Discovery Mechanism - 8. **Mint tokens** - send 1000 tokens to the created account +Traditional intent-based protocols essentially function as cross-chain limit orders. If the order is profitable, solvers will compete to fulfill it, leading to MEV-like competition focused on speed. While functional, this methodology presents two clear inefficiencies and drawbacks. - ```bash - spl-token mint INSERT_TOKEN_ADDRESS 1000 - ``` +First, they lack a competitive price discovery mechanism as limit order prices are typically determined through centralized off-chain systems. Second, in this MEV-like market structure, only a single solver can win, while the others lose out on transaction fees. This dynamic of deadweight loss results in solvers prioritizing high-margin orders, ultimately resulting in elevated fees for end-users without commensurate benefits. - !!! note - NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. +Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. -2. **Choose your [deployment model](TODO){target=\_blank}**: +![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program +### Protocol Flow: How It Works -3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +1. **Initiation** - the user creates an order by signing a transaction that locks one of the primary assets (USDC or ETH) into the Mayan smart contract, specifying the desired outcome. -Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. + !!!note + If the input asset is not a primary asset, it is converted into a primary asset within the same transaction before the order is submitted. -By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. + Each order includes properties such as destination chain, destination wallet address, output token address, minimum output amount, gas drop amount, deadline, and 32 bytes of random hex to prevent collisions. A Keccak-256 hash is then calculated to identify the order -## Set Up NTT +2. **Auction** - solvers observe on-chain data or subscribe to the Mayan explorer web socket (solvers using the Mayan explorer verify the order's integrity by checking the data against the on-chain hash). Once the new order is verified, an on-chain auction on Solana is initiated by passing the order ID and the bid amount, which cannot be lower than the minimum amount. Other solvers can increase the bid by submitting a higher amount before the auction ends +3. **Fulfillment** - the auction ends three seconds after the initial bid. Once the auction ends, the winning solver can execute an instruction that passes their wallet address on the destination chain. This triggers a Wormhole message containing the order ID and the winner's wallet address. Wormhole Guardians then sign this message, allowing the winning solver to fulfill the order on the destination chain by submitting proof of their win and the promised amount to the Mayan contract before the deadline. The Mayan contract deducts a protocol fee (currently 3 basis points) and a referral fee (if applicable), transferring the remaining amount to the user's destination wallet. It also triggers a Wormhole message as proof of fulfillment +4. **Settlement** - after the Wormhole Guardians sign the fulfillment message, the winning solver can submit this message on the source chain to unlock the user's funds and transfer them to their own wallet. Upon fulfillment, the solver has the option to delay triggering a Wormhole message immediately. Instead, they can batch the proofs and, once the batch reaches a certain threshold, issue a batched proof to unlock all orders simultaneously, saving on gas fees -To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. +## Mayan MCTP -The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. -1. **Create a new NTT project** - set up a deployment workspace +![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) - ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME - ``` +### Protocol Flow: How It Works -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +1. **Initiation** - the user creates an order by signing a transaction that locks one USDC into the Mayan smart contract, specifying the desired outcome. - === "Mainnet" + !!!note + If the input asset is not USDC, it is converted into a primary asset within the same transaction before the order is submitted. + + The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash - ```bash - ntt init Mainnet - ``` +2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} +3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules - === "Testnet" +The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. - ```bash - ntt init Testnet - ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. +## Where to Go Next -### Generate an NTT Program Key Pair +- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide +- To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial +--- END CONTENT --- -Create a unique key pair for the NTT program: +Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement FAQs +description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. +categories: Settlement, Transfer +--- -```bash -solana-keygen grind --starts-with ntt:1 --ignore-case -``` +# Wormhole Settlement FAQs -### Set Mint Authority +## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? -If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. +Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. -If you want to use hub-and-spoke, skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt). +## What happens if no solver participates in the auction? -Before updating the mint authority, you must create metadata for your SPL token. You can visit this repository to see an example of [how to create metadata for your SPL token](https://github.com/wormhole-foundation/demo-metaplex-metadata/blob/main/src/token-metadata.ts){target=\_blank}. +If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. -Follow these steps to set the mint authority using the NTT CLI: +## What guarantees does Wormhole Settlement provide for message execution? -1. **Derive the token authority** - generate the PDA, which will manage token minting +After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). - ```bash - ntt solana token-authority INSERT_YOUR_NTT_PROGRAM_KEY_PAIR - ``` +If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. +--- END CONTENT --- -2. **Set SPL token mint authority** - delegate minting control to the derived PDA +Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ +--- BEGIN CONTENT --- +TODO +--- END CONTENT --- - ```bash - spl-token authorize INSERT_TOKEN_ADDRESS mint INSERT_DERIVED_PDA - ``` +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Liquidity Layer +description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. +categories: Settlement, Transfer +--- -## Deploy and Configure NTT +# Build on the Wormhole Liquidity Layer -!!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. +## Introduction +The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. -After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: +## EVM Functions -1. **Deploy NTT to Solana** - run the appropriate command based on your deployment mode: +The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - === "Burn-and-Mint" +See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. - ```bash - ntt add-chain Solana --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` +### Fast Market Order - === "Hub-and-Spoke" +The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` - ```bash - ntt add-chain Solana --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON - ``` +```solidity title="`placeFastMarketOrder` Interface" +function placeFastMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, + uint128 maxFee, + uint32 deadline +) external payable returns (uint64 sequence, uint64 fastSequence); +``` - You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`. +??? interface "Parameters `placeFastMarketOrder()`" -2. **Verify deployment status** - after deployment, check if your `deployment.json` file matches the on-chain configuration using the following command: + `amountIn` ++"uint128"++ - ```bash - ntt status - ``` + The amount to transfer. - If needed, sync your local configuration with the on-chain state: + --- - ```bash - ntt pull - ``` + `targetChain` ++"uint16"++ -3. **Configure inbound and outbound rate limits** - by default, the inbound and outbound limits are set to `0` and must be updated before deployment. For EVM chains, values must be set using 18 decimals, while Solana uses nine decimals. + Target chain ID. - Open your `deployment.json` file and adjust the values based on your use case: + --- - ```json - "inbound": { - "Sepolia": "1000.000000000" // inbound limit from Sepolia to Solana - }, - "outbound": { - "Sepolia": "1000.000000000" // outbound limit from Solana to Sepolia - } - ``` + `redeemer` ++"bytes32"++ -4. **Push the final deployment** - once rate limits are set, push the deployment to Solana using the specified key pair to cover gas fees + Redeemer contract address. - ```bash - ntt push --payer INSERT_YOUR_KEYPAIR_JSON - ``` - -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. + --- -## Where to Go Next + `redeemerMessage` ++"bytes"++ -
    + An arbitrary payload for the redeemer. -- :octicons-globe-16:{ .lg .middle } **Deploy NTT on EVM Chains** + --- - --- + `maxFee` ++"uint128"++ - After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. + The maximum fee the user wants to pay to execute a fast transfer. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + --- -- :octicons-tools-16:{ .lg .middle } **Test Your Deployment** + `deadline` ++"uint32"++ - --- + The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. - Follow the NTT Post Deployment Guide for integration examples and testing instructions. +The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} +### Market Order -- :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** +The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. - --- +```solidity title="`placeMarketOrder` Interface" +function placeMarketOrder( + uint128 amountIn, + uint16 targetChain, + bytes32 redeemer, + bytes calldata redeemerMessage, +) external payable returns (uint64 sequence, uint64 protocolSequence); +``` - Configure Wormhole Connect, a plug-and-play bridging UI, to enable multichain transfers for your token. +??? interface "Parameters `placeMarketOrder()`" - [:custom-arrow: Use Connect to Integrate NTT](/docs/products/connect/overview/){target=\_blank} + `amountIn` ++"uint128"++ -- :octicons-question-16:{ .lg .middle } **View FAQs** + The amount to transfer. --- - Find answers to common questions about NTT. + `targetChain` ++"uint16"++ - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + Target chain ID. -- :octicons-question-16:{ .lg .middle } **View FAQs** + --- + + `redeemer` ++"bytes32"++ + + Redeemer contract address. --- - Find answers to common questions about NTT. + `redeemerMessage` ++"bytes"++ - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + An arbitrary payload for the redeemer. -
    +The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/evm-launchpad/ +Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ --- BEGIN CONTENT --- --- -title: Deploy Native Token Transfers with Launchpad -description: Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. -categories: NTT, Transfer +title: Wormhole Settlement Solver +description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. +categories: Settlement, Transfer --- -# Deploy Native Token Transfers with Launchpad +# Run a Wormhole Settlement Solver ## Introduction -The [Native Token Transfers (NTT) Launchpad](https://ntt.wormhole.com/){target=\_blank} is a Wormhole-managed UI application that provides a step-by-step interface for deploying NTT across multiple blockchains. +This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. -Instead of manually deploying contracts on each chain, configuring relayers, and managing cross-chain communication, you can quickly launch or expand tokens with just a few clicks. +A Solver is an off-chain agent responsible for: -The Launchpad automates deployment, reducing complexity and saving time. +- Listening to cross-chain transfer requests sent over Wormhole +- Bidding in auctions (on Solana) to fulfill each request +- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain +- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -This guide covers: +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. - - Launching a new cross-chain token - - Expanding an existing token for NTT - - Managing tokens via the dashboard and settings +## Background -## Prerequisites +The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: - - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\_blank}, [Phantom](https://phantom.com/){target=\_blank}, etc.) - - Minimum ETH (or equivalent) for gas fees per deployment +1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details +2. `bid` - allows a solver to place or update a bid on the active auction +3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. +4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners -## Supported Blockchains +These instructions work together to carry out the auction as follows: -The NTT Launchpad currently supports deployments on the following mainnet chains: +- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity +- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver +- The originating solver can repurpose the returned funds and use them to improve their bid +- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - - Ethereum - - Arbitrum One - - Base - - Berachain - - Blast - - BNB Smart Chain - - Ink - - Optimism Mainnet - - Polygon +When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. -## Choose Your Path +If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. -Once ready, choose an option to proceed: +## Testnet Example Solver - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract +You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. -## Launch a Cross-Chain Token +!!!warning + This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. -Deploy a new NTT-compatible token that can be transferred across multiple chains. This process sets up your token on a home network and deploys it to additional blockchains. Follow the below steps to get started: +### Prerequisites -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** +In order to build and install dependencies locally in this repo, you will need: - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) - -2. Select **Launch a Cross-Chain Token** +- node v20.18.1 +- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp) +Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: -3. Set the token details: - 1. Select the **home network** from the dropdown menu - 2. Enter the **name** for the token - 3. Enter the **symbol** of the token - 4. Provide the **initial supply** - 5. To the token details, click **Next** +```sh +make dependencies +``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp) +### Set up Config -4. Select the deployment chains: - 1. The home network where your token will be deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** +The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp) +```json title="config.json" +{ + "environment": "Testnet", + "zmqChannels": { + "fastVaa": "tcp://localhost:6001", + "finalizedVaa": "tcp://localhost:6002" + }, + "publisher": { + "log": { + "level": "info" + }, + "vaaSpy": { + "host": "localhost:7073", + "enableObservationCleanup": true, + "observationSeenThresholdMs": 1500000, + "observationCleanupIntervalMs": 500, + "observationsToRemovePerInterval": 5, + "delayedThresholdMs": 60000 + } + }, + "solver": { + "log": { + "level": "info", + "filename": "logs/solver.log" + }, + "connection": { + "rpc": "", + "maxTransactionsPerSecond": 5, + "commitment": "processed", + "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", + "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", + "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + "knownAtaOwners": [ + "Payer11111111111111111111111111111111111111", + "Payer11111111111111111111111111111111111112", + "Payer11111111111111111111111111111111111113" + ] + } + }, + "routerEndpoints": [ + { + "chain": "Sepolia", + "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Avalanche", + "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "OptimismSepolia", + "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "ArbitrumSepolia", + "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "BaseSepolia", + "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + }, + { + "chain": "Polygon", + "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", + "rollbackRisk": 0.0069, + "offerEdge": 0.042 + } + ] +} +``` -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction +The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) +### Listen to Activity -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet +The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) +```sh +NETWORK=testnet CONFIG=path/to/config.json make run-publisher +``` -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step +You should see output resembling: -8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token. +
    + Start logging with info level. + 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet + 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 + 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 + 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 +
    -## Expand Your Existing Token +To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: -Expand an existing token to support NTT across multiple chains. This process integrates your deployed token with NTT without modifying its original contract. Follow the steps below to get started: +=== "Linux" -1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank}, connect your wallet, and click **Get Started** + ```sh + sudo sysctl -w net.core.rmem_max=2097152 + sudo sysctl -w net.core.rmem_default=2097152 + ``` - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp) - -2. Select **Expand Your Existing Token** - - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp) - -3. Enter the token details: - 1. Choose the home network where your token is already deployed (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 3. To continue, click **Next** - - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp) - -4. Select the chains to deploy your token to: - 1. The home network where your token is already deployed will be populated (e.g., Optimism) - 2. Choose any additional chains to deploy your token to (e.g., Base) - 1. Click **Next** - - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp) - -5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction - - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp) - -6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet - - ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp) - -7. Repeat the previous step to deploy the token on the second chain (Base). The supply of tokens on Base will be zero since the tokens were all minted on Optimism in the previous step - -8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details - -## Explore the Launchpad Dashboard +=== "MacOS" -To access the **Dashboard** from the [Launchpad home page](https://ntt.wormhole.com/){target=\_blank}, click on **Manage Deployment**. Here, you can view deployment status, monitor supply across chains, and configure transfer settings. + ```sh + sudo sysctl -w net.inet.udp.recvspace=2097152 + ``` -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp) +### Running the Example Solver -The dashboard provides a high-level view of your token across all deployed chains, including: +Using the same config for your publisher, run the example solver with the command below. - - Token addresses for each chain - - Supply distribution visualization - - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings) +```sh +CONFIG=path/to/config.json make run-solver +``` -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp) +It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. -## Settings +This process reads the following environment variables: -The **Settings** page allows you to configure security parameters, role management, and transfer limits for your deployed token. You can switch between chains to manage these settings independently for each deployment. +```sh +SOLANA_PRIVATE_KEY_1= +SOLANA_PRIVATE_KEY_2= +SOLANA_PRIVATE_KEY_3= +SOLANA_PRIVATE_KEY_4= +SOLANA_PRIVATE_KEY_5= +``` -### Chain Management +At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. -Use the drop-down menu at the top to select the chain you want to configure. The available options correspond to the chains where your token has already been deployed. Once selected, the page displays token details specific to that chain. +The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. -From this section, you can also: +Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain +An address lookup table is required to execute some transactions. Use the command below to create one. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) +```sh +CONFIG=path/to/config.json make create-lut +``` -### Role Management +`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. -This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. +The example solver has the following toggles depending on which orders you want to fulfill: - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers +- `enableCctpOrderPipeline()` +- `enableLocalOrderPipeline()` +- `enablePlaceInitialOffer()` +- `enableImproveOffer()` -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) +See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. -### Security Threshold +This example solver does NOT do the following: -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called +- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it +- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want +--- END CONTENT --- -A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. +Doc-Content: https://wormhole.com/docs/products/settlement/overview/ +--- BEGIN CONTENT --- +--- +title: Settlement Overview +description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. +categories: Settlement, Transfer +--- - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers +# Settlement Overview -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) +Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. -### Peer Chains Limits +Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. -Define the transfer restrictions for each connected network. You can adjust: +It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains +## Key Features -Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. +- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. +- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. +- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. +- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. -![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp) ---- END CONTENT --- +## How It Works -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/overview/ ---- BEGIN CONTENT --- ---- -title: Native Token Transfers Overview -description: With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. -categories: NTT, Transfer ---- +At the core of Settlement are two components: -## Native Token Transfers Overview +- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. +- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. -Native Token Transfers (NTT) provides an adaptable framework for transferring your native tokens across different blockchains. Unlike traditional wrapped assets, NTT maintains your token's native properties on every chain. This ensures that you retain complete control over crucial aspects, such as metadata, ownership, upgradeability, and custom features. +Settlement leverages the following three integrated protocols. -## Key Features +### Mayan Swift -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. +The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. -## Deployment Models +1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. +2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. +3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. -NTT offers two operational modes for your existing tokens: +```mermaid +sequenceDiagram + participant User + participant Solver_ARB as Solver (Arbitrum) + participant Escrow + participant Wormhole + participant Solver_SOL as Solver (Solana) + participant Aggregator -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token + Note over User,Aggregator: User has ARB and wants WIF -## Supported Token Standards + User->>Solver_ARB: Submit intent (ARB → WIF) + Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH + Escrow-->>Wormhole: Emits VAA + Wormhole-->>Solver_SOL: Delivers VAA + Solver_SOL->>Aggregator: Releases SOL and swaps to WIF + Aggregator->>Solver_SOL: Receives WIF + Solver_SOL->>User: Sends WIF + User-->>Wormhole: Emits final VAA + Wormhole-->>Escrow: Confirms receipt + Escrow->>Solver_ARB: Releases ETH to solver +``` -Native Token Transfers (NTT) primarily support ERC-20 tokens, the most widely used standard for fungible assets on Ethereum and other EVM-compatible chains, including ERC-20 Burnable tokens, which can be burned on the source chain during cross-chain transfers when required. It also supports fungible SPL tokens on Solana for secure cross-chain transfers. +### Liquidity Layer -The NttManager is a contract that oversees the secure and reliable transfer of native tokens across supported blockchains. It leverages the standard IERC20 interface and OpenZeppelin’s SafeERC20 library to interact with these tokens securely across chains. +The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. -NTT does not currently support token standards like ERC-721 (non-fungible tokens), ERC-1155 (a multi-token standard), or SPL-based tokens, such as Metaplex NFTs. Support is currently limited to ERC-20 tokens. +### Mayan MCTP -## Deployment Process +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. -Here's a breakdown of the key steps involved when deploying NTT: +### One Integration, Three Ways -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed +Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. -## Use Cases +By default, Settlement integrates all three: -- **Cross-Chain Swaps and Liquidity Aggregation** +- The SDK automatically resolves the best route for each transfer. +- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. +- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution +Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. -- **Borrowing and Lending Across Chains** +To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time +## Use Cases -- **Gas Abstraction** +- **Cross-Chain Perpetuals** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains -- **Cross-Chain Payment Widgets** +- **Bridging Intent Library** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls -- **Cross-Chain Staking** +- **Multichain Prediction Markets** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains + - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state ## Next Steps -Follow these steps to get started with NTT: +Start building with Settlement or dive deeper into specific components: -[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] +- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. +- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ +Doc-Content: https://wormhole.com/docs/products/settlement/tutorials/.settlement-routes/ --- BEGIN CONTENT --- --- -title: NTT CLI Commands -description: A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -categories: NTT, Transfer +title: Wormhole Settlements +description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. --- -# NTT CLI Commands +# Integrate Wormhole Settlement Routes Using the SDK ## Introduction -The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. +This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. +## Prerequisites -## Table of Commands +Before beginning this project, make sure you have the following: -The following table lists the available NTT CLI commands, descriptions, and examples. +- **Wormhole SDK Route package** - installed using your preferred package manager -To explore detailed information about any NTT CLI command, including its options and examples, you can append `--help` to the command. This will display a comprehensive guide for the specific command. + To install the package with npm, run the following command in your terminal: -### General Commands + ```sh + npm install @mayan-finance/wormhole-sdk-route + ``` -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
    ` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | + Alternatively, clone the repository and install dependencies: -### Configuration Commands + ```sh + git clone https://github.com/mayan-finance/wormhole-sdk-route.git + cd wormhole-sdk-route + npm install + ``` -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| +- **Data for parameters** - you will need: + + - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains + - An contract address for the token you want to swap and the token you want to receive on the destination chain -### Solana Commands +## Configure and Setup -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| +To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: -## Where to Go Next +- `sourceChain` - identifier for the chain where the swap begins +- `destinationChain` - identifier for the target chain +- `inputTokenAddress` - address of the token you want to swap +- `outputTokenAddress` - identifier/address of the desired token on the destination chain +- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) +- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) -
    +```ts +import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; +const config: SwapRouteConfig = { + sourceChain: 'ethereum', + destinationChain: 'solana', + inputTokenAddress: '0xYourInputTokenAddress', + outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana + amount: '1000000000000000000', // For instance, 1 token in wei + slippageTolerance: 0.005, // 0.5% slippage tolerance + // Additional parameters may be included as needed +}; -- :octicons-gear-16:{ .lg .middle } **Configure NTT** +const swapRoute = new SwapRoute(config); +``` - --- +## Execute a Swap - Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting. +Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. - [:custom-arrow: Configure your NTT deployment](/docs/products/native-token-transfers/configuration/access-control/) +### Fetch the Swap Route -- :octicons-question-16:{ .lg .middle } **NTT FAQs** +Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: - --- +```ts +async function getSwapDetails() { + try { + const routeDetails = await swapRoute.getRoute(); + console.log('Optimal Swap Route:', routeDetails); + return routeDetails; + } catch (error) { + console.error('Error fetching swap route:', error); + throw error; + } +} - Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges. +getSwapDetails(); +``` - [:custom-arrow: Check out the FAQs](/docs/products/native-token-transfers/faqs/) +### Execute the Swap Transaction -
    ---- END CONTENT --- +Once the route is confirmed, execute the swap: -Doc-Content: https://wormhole.com/docs/products/native-token-transfers/troubleshooting/ ---- BEGIN CONTENT --- ---- -title: Troubleshooting NTT Deployment -description: Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. -categories: NTT, Transfer ---- +```ts +async function executeSwap() { + try { + const txResponse = await swapRoute.executeSwap(); + console.log('Swap executed successfully:', txResponse); + // Further transaction handling (e.g., waiting for confirmation) can be added here. + } catch (error) { + console.error('Swap execution failed:', error); + } +} -# Troubleshooting NTT Deployment +executeSwap(); +``` -If you encounter issues during the NTT deployment process, check the following common points: +## Complete Example Integration -- **Solana and Anchor versions** - ensure you are using the expected versions of Solana and Anchor as outlined in the [deployment page](/docs/products/native-token-transfers/guides/deploy-to-solana/#install-dependencies){target=\_blank} - - [Solana](https://docs.solanalabs.com/cli/install){target=\_blank} **`{{ ntt.solana_cli_version }}`** - - [Anchor](https://www.anchor-lang.com/docs/installation){target=\_blank} **`{{ ntt.anchor_version }}`** -- **Token compliance on EVM** - verify that your token is an ERC20 token on the EVM chain -- **Mint authority transfer** - - **For burn or spoke tokens on Solana** - ensure the token mint authority was transferred as described in the [set SPL Token Mint Authority](/docs/products/native-token-transfers/guides/deploy-to-solana/#set-spl-token-mint-authority){target=\_blank} section - - **For EVM tokens** - confirm the token minter was set to the NTT Manager. Refer to the [set Token Minter to NTT Manager](/docs/products/native-token-transfers/guides/deploy-to-evm/#set-token-minter-to-ntt-manager){target=\_blank} section for details -- **Decimal configuration** - run `ntt pull` to correctly configure the decimals in your `deployment.json` file. More details in the [configure NTT](/docs/products/native-token-transfers/guides/deploy-to-solana/#configure-ntt){target=\_blank} section -- **Rate limit configuration** - increase your rate limits to a value greater than zero. A rate limit of zero can cause transactions to get stuck. Learn more on how to [configure rate limits](/docs/products/native-token-transfers/guides/deploy-to-evm/#configure-ntt){target=\_blank} -- **Docker environment based on Ubuntu 20.04 with all dependencies required for Wormhole NTT CLI development** - run `docker compose up -d` to start the container in your terminal from the directory containing the `docker-compose.yml` file +Below is a complete example that puts together configuration, route fetching, and swap execution: - ???- interface "Dockerfile" +```ts +import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - ```Dockerfile - FROM ubuntu:20.04 - # Set environment variables to prevent interactive prompts during installation - ENV DEBIAN_FRONTEND=noninteractive +async function performSwap() { + // Configure the swap parameters + const config: SwapRouteConfig = { + sourceChain: 'ethereum', + destinationChain: 'solana', + inputTokenAddress: '0xYourInputTokenAddress', + outputTokenAddress: 'So11111111111111111111111111111111111111112', + amount: '1000000000000000000', + slippageTolerance: 0.005, + // Include additional settings as needed + }; - # Update and install necessary dependencies - RUN apt-get update && apt-get install -y \ - curl \ - wget \ - git \ - build-essential \ - libssl-dev \ - libudev-dev \ - pkg-config \ - python3 \ - python3-pip \ - software-properties-common \ - ca-certificates \ - unzip \ - clang \ - cmake \ - protobuf-compiler \ - && apt-get clean && rm -rf /var/lib/apt/lists/* + // Initialize the swap route + const swapRoute = new SwapRoute(config); - # Install Rust - RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - ENV PATH="/root/.cargo/bin:$PATH" + try { + // Retrieve the optimal swap route details + const routeDetails = await swapRoute.getRoute(); + console.log('Optimal Swap Route:', routeDetails); - # Install Solana CLI ({{ntt.solana_cli_version}}) - RUN sh -c "$(curl -sSfL https://release.solana.com/{{ntt.solana_cli_version}}/install)" - ENV PATH="/root/.local/share/solana/install/active_release/bin:$PATH" + // Execute the swap transaction + const txResponse = await swapRoute.executeSwap(); + console.log('Swap Transaction Response:', txResponse); + } catch (error) { + console.error('An error occurred during the swap process:', error); + } +} - # Install Anchor using avm - RUN cargo install --git https://github.com/coral-xyz/anchor avm --locked --force \ - && avm install 0.29.0 \ - && avm use 0.29.0 - ENV PATH="/root/.avm/bin:$PATH" +performSwap(); +``` +## Error Handling and Troubleshooting - ENV NVM_DIR=/root/.nvm - RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install 22 \ - && nvm use 22 \ - && nvm alias default 22 - ENV PATH="$NVM_DIR/versions/node/v22.12.0/bin:$PATH" +- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable +- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting +- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: - # Install Bun - RUN curl -fsSL https://bun.sh/install | bash - ENV PATH="/root/.bun/bin:$PATH" + ```ts + class MayanRefRoute extends MayanRoute { + override referrerAddress(): ReferrerAddresses | undefined { + return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; + } + } + ``` +--- END CONTENT --- - # Install Foundry - RUN curl -L https://foundry.paradigm.xyz | bash - ENV PATH="/root/.foundry/bin:${PATH}" - RUN /bin/bash -c "source /root/.bashrc && foundryup" +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Payload Structure +description: Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. +categories: Token-Bridge, Transfers +--- - # Install Wormhole NTT CLI - RUN curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash +# Message and Payload Structure - # Add a default working directory - WORKDIR /app +To enable secure and flexible cross-chain token transfers, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} defines a set of standardized payloads. These payloads are embedded in [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} and processed by bridge contracts on the source and destination chains. Each payload has a unique format and serves a specific role in the lifecycle of token bridging. - # Expose port for development if needed - EXPOSE 8899 +This page outlines each payload type in detail. - # Entry point for the container - CMD ["bash"] - ``` +## Transfer - ???- interface "docker-compose.yml" - ```yml - services: - portal-ntt: - build: - context: . - dockerfile: Dockerfile - platform: linux/amd64 - volumes: - - ./src:/app - working_dir: /app - tty: true - ``` ---- END CONTENT --- +The `Transfer` payload (ID = `1`) is the core mechanism for moving tokens across chains. It is emitted when a user locks or burns tokens on the source chain. On the destination chain, it instructs the bridge to either mint a wrapped token or release native tokens from custody. -Doc-Content: https://wormhole.com/docs/products/products/ ---- BEGIN CONTENT --- ---- -title: Compare Wormhole's Cross-Chain Solutions -description: Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -categories: Transfer, Basics ---- +```text +PayloadID uint8 = 1 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +Fee uint256 +``` -# Products +??? interface "Parameters" -Wormhole provides a comprehensive suite of cross-chain solutions, enabling seamless asset transfers, data retrieval, and governance across blockchain ecosystems. + `PayloadID` ++"uint8"++ -Wormhole provides multiple options for asset transfers: Connect for a plug-and-play bridging UI, Native Token Transfers (NTT) for moving native assets without wrapped representations, and Token Bridge for a secure lock-and-mint mechanism. + Value must be `1`, indicating a `Transfer` operation. -Beyond transfers, Wormhole extends interoperability with tools for cross-chain data access, decentralized governance, and an intent-based protocol through Wormhole Settlement. + --- -## Transfer Products + `Amount` ++"uint256"++ -Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. + Amount being transferred, truncated to 8 decimals for consistency across all chains. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods + --- -
    + `TokenAddress` ++"bytes32"++ -::spantable:: + Address of the token. Left-zero-padded if shorter than 32 bytes + + --- -| | Criteria | NTT | Token Bridge | Settlement | -|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------| -| Supported Transfer Types @span | Token Transfers | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| | Token Transfers with Payloads | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Supported Assets @span | Wrapped Assets | :x: | :white_check_mark: | :white_check_mark: | -| | Native Assets | :white_check_mark: | :x: | :white_check_mark: | -| | ERC-721s (NFTs) | :x: | :white_check_mark: | :white_check_mark: | -| Features @span | Out-of-the-Box UI | :x: | :x: | :white_check_mark: | -| | Event-Based Actions | :white_check_mark: | :white_check_mark: | :x: | -| | Intent-Based Execution | :x: | :x: | :white_check_mark: | -| | Fast Settlement | :x: | :x: | :white_check_mark: | -| | Liquidity Optimization | :x: | :x: | :white_check_mark: | -| Integration Details @span | | | | | -| Requirements @span | Contract Deployment | :white_check_mark: | :x: |:x: | -| Ease of Integration | Implementation Complexity | :green_circle: :green_circle: :white_circle:
    Moderate | :green_circle: :green_circle: :white_circle:
    Moderate |:green_circle: :white_circle: :white_circle:
    Low | -| Technology @span | Supported Languages | Solidity, Rust | Solidity, Rust, TypeScript | TypeScript | + `TokenChain` ++"uint16"++ -::end-spantable:: + Chain ID of the token. + + --- -
    + `To` ++"bytes32"++ -Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. + Address of the recipient. Left-zero-padded if shorter than 32 bytes. + + --- -## Bridging UI + `ToChain` ++"uint16"++ -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. + Chain ID of the recipient. + + --- -## Real-time Data + `Fee` ++"uint256"++ -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. + Amount of tokens that the user is willing to pay as relayer fee. Must be less than Amount. Optional and can be claimed by relayers who submit the VAA on the target chain. + -## Multichain Governance +To keep `Transfer` messages small, they don't carry all the token's metadata. However, this means that before a token can be transferred to a new chain for the first time, the metadata needs to be bridged, and the wrapped asset needs to be created. Metadata, in this case, includes the number of decimals, which is a core requirement for instantiating a token. -[**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. ---- END CONTENT --- +## AssetMeta -Doc-Content: https://wormhole.com/docs/products/queries/concepts/rpc-basics/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +Before a token can be transferred to a new chain for the first time, its metadata must be attested using the `AssetMeta` payload (ID = `2`). This ensures proper decimal precision and display. -Doc-Content: https://wormhole.com/docs/products/queries/faqs/ ---- BEGIN CONTENT --- ---- -title: Queries FAQs -description: Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. -categories: Queries ---- +```text +PayloadID uint8 = 2 +TokenAddress [32]uint8 +TokenChain uint16 +Decimals uint8 +Symbol [32]uint8 +Name [32]uint8 +``` -# Wormhole Queries FAQs +??? interface "Parameters" -## What libraries are available to handle queries? + `PayloadID` ++"uint8"++ - - The [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} can be used to create query requests, mock query responses for testing, and parse query responses. The SDK also includes utilities for posting query responses + Value must be `2`, indicating a `AssetMeta` operation. -- The [Solidity `QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} can be used to parse and verify query responses on EVM chains. See the [Solana Stake Pool](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} repository as an example use case + --- -- [`QueryRequestBuilder.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/testing/QueryRequestBuilder.sol){target=\_blank} can be used for mocking query requests and responses in Forge tests + `TokenAddress` ++"[32]uint8"++ -- The [Go query package](https://github.com/wormhole-foundation/wormhole/tree/main/node/pkg/query){target=\_blank} can also be used to create query requests and parse query responses + Address of the token. Left-zero-padded if shorter than 32 bytes. -!!! note - A Rust SDK for Solana is being actively investigated by the Wormhole contributors. See the [Solana Queries Verification](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} repository as a proof of concept. + --- -## Are there any query examples? + `TokenChain` ++"uint16"++ -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: + Chain ID of the token. -- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} -- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} -- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\_blank} -- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\_blank} + --- -## What is the format of the response signature? + `Decimals` ++"uint8"++ -The Guardian node calculates an ECDSA signature using [`Sign` function of the crypto package](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.21/crypto#Sign){target=\_blank} where the digest hash is: + Number of decimals the token uses on its native chain (not truncated to 8). -```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` + --- -See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. + `Symbol` ++"[32]uint8"++ -!!! note - If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. + Symbol of the token, UTF-8 encoded and padded to 32 bytes. -## Can anyone run a query proxy server? + --- -Permissions for Query Proxy are managed by the Guardians. The Guardian nodes are configured to only listen to a set of allow-listed proxies. However, it is possible that this restriction may be lifted in the future and/or more proxies could be added. + `Name` ++"[32]uint8"++ -It is also important to note that the proxies don't impact the verifiability of the request or result, i.e., their role in the process is trustless. + Name of the token, UTF-8 encoded and padded to 32 bytes. -## What Does Queries Offer over an RPC Service +## TransferWithPayload -Wormhole Queries provides on-demand, attested, on-chain, verifiable RPC results. Each Guardian independently executes the specified query and returns the result and their signature. The proxy handles aggregating the results and signatures, giving you a single result (all within one REST call) with a quorum of signatures suitable for on-chain submission, parsing, and verification using one of our examples or SDKs. ---- END CONTENT --- +The `TransferWithPayload` payload (ID = `3`) extends the standard token transfer by allowing developers to include arbitrary data. This enables interactions with destination chain smart contracts, such as triggering swaps or staking. -Doc-Content: https://wormhole.com/docs/products/queries/get-started/ ---- BEGIN CONTENT --- ---- -title: Get Started with Queries -description: Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. -categories: Queries ---- +```text +PayloadID uint8 = 3 +Amount uint256 +TokenAddress bytes32 +TokenChain uint16 +To bytes32 +ToChain uint16 +FromAddress bytes32 +Payload bytes +``` -# Get Started with Queries +??? interface "Parameters" -## Introduction + `PayloadID` ++"uint8"++ -[Queries](/docs/products/queries/overview) lets you fetch on-chain data from supported blockchains using `eth_call`-style requests without submitting transactions or paying gas. The Guardian network signs the result, making it verifiable and suitable for use on-chain. + Value must be `3`, indicating a `TransferWithPayload` operation. -This guide walks you through requesting an API key, constructing your first query using the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, and decoding the result. + --- -## Prerequisites + `Amount` ++"uint256"++ -Before you begin, make sure you have the following: + Amount being transferred, truncated to 8 decimals. - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} - - A basic understanding of JavaScript or TypeScript - - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia) - - A Wormhole Queries API key + --- -## Request an API Key + `TokenAddress` ++"bytes32"++ -Wormhole Queries is in closed beta, but you can start building today. + Address of the token. Left-zero-padded if shorter than 32 bytes. -To interact with the system, you will use the Query Proxy. This hosted service receives your query, routes it to the appropriate chain, and returns a signed, verifiable response from the Guardian network. The Query Proxy allows you to fetch on-chain data without infrastructure overhead. + --- -To request access, join the beta by filling out the [access form](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}. Once approved, you will receive an API key via email. + `TokenChain` ++"uint16"++ -## Construct a Query and Decode the Response + Chain ID of the token. -Using the Wormhole Query Proxy, you will write a lightweight script to query a token contract's `name()` on Ethereum Sepolia. The response is signed by the Guardian network and locally decoded for use in your application. + --- -1. Create a new directory for your script and initialize a Node.js project: + `To` ++"bytes32"++ - ```bash - mkdir queries - cd queries - npm init -y - ``` + Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes -2. Add the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank}, [Axios](https://www.npmjs.com/package/axios){target=\_blank}, [Web3](https://www.npmjs.com/package/web3){target=\_blank}, and helper tools: + --- - ```bash - npm install axios web3 @wormhole-foundation/wormhole-query-sdk - npm install -D tsx typescript - ``` + `ToChain` ++"uint16"++ -3. Add a new `query.ts` script where you will write and run your query logic: + Chain ID of the recipient. - ```bash - touch query.ts - ``` + --- -4. Paste the following script into `query.ts` to build and submit a query to the token contract's `name()` function on Ethereum Sepolia, then decode the Guardian-signed response: + `FromAddress` ++"bytes32"++ - ```typescript - // Import the SDK types and helpers for making the query -import { - EthCallQueryRequest, - EthCallQueryResponse, - PerChainQueryRequest, - QueryRequest, - QueryResponse, -} from '@wormhole-foundation/wormhole-query-sdk'; -import axios from 'axios'; -import * as eth from 'web3'; + Address of the sender on the source chain. -// Define the endpoint and query parameters -const query_url = 'https://testnet.query.wormhole.com/v1/query'; -const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public'; -const chain_id = 10002; // Sepolia (Wormhole chain ID) -const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract -const data = '0x06fdde03'; // function selector for `name()` + --- -// Load your API key from environment variables -const apiKey = process.env.API_KEY; -if (!apiKey) throw new Error('API_KEY is not set in your environment'); + `Payload` ++"bytes"++ -(async () => { - // Fetch the latest block number (required to anchor the query) - const latestBlock = ( - await axios.post(rpc, { - method: 'eth_getBlockByNumber', - params: ['latest', false], - id: 1, - jsonrpc: '2.0', - }) - ).data?.result?.number; + Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic. - // Build the query targeting the token contract's name() function - const request = new QueryRequest(1, [ - new PerChainQueryRequest( - chain_id, - new EthCallQueryRequest(latestBlock, [{ to: token, data: data }]) - ), - ]); - const serialized = request.serialize(); - // Send the query to the Wormhole Query Proxy - const response = await axios.post( - query_url, - { bytes: Buffer.from(serialized).toString('hex') }, - { headers: { 'X-API-Key': apiKey } } - ); +Unlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly. - // Decode the response returned by the Guardian network - const queryResponse = QueryResponse.from(response.data.bytes); - const chainResponse = queryResponse.responses[0] - .response as EthCallQueryResponse; - const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]); +## RegisterChain - // Output the results - console.log('\n\nParsed chain response:'); - console.log(chainResponse); - console.log('\nToken name:', name); -})(); - ``` +The `RegisterChain` governance payload (Action ID = `1`) registers a Token Bridge emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers. -5. Use your API key to execute the script: +```text +Module [32]byte +Action uint8 = 1 +ChainId uint16 - ```bash - API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts - ``` +EmitterChainID uint16 +EmitterAddress [32]uint8 +``` -The expected output should be similar to this: +??? interface "Parameters" -
    -API_KEY=123_456_789 npx tsx query.ts -Parsed chain response: -EthCallQueryResponse { -blockNumber: 8193548n, -blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8', -blockTime: 1745595132000000n, -results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000'] -} - -Token name: USDC - -
    - -## Next Steps + `Module` ++"[32]byte"++ -Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: + Module identifier. Left-padded with `TokenBridge` for Token Bridge. - - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM - - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually - - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts + --- -Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. ---- END CONTENT --- + `Action` ++"uint8"++ -Doc-Content: https://wormhole.com/docs/products/queries/guides/construct-a-query/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- + Value must be `1`, indicating a `RegisterChain` operation. -Doc-Content: https://wormhole.com/docs/products/queries/guides/mock-a-query/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- + --- -Doc-Content: https://wormhole.com/docs/products/queries/guides/query-request/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- + `ChainID` ++"uint16"++ -Doc-Content: https://wormhole.com/docs/products/queries/guides/submit-response/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- + The chain where this governance action should be applied. `0` is a valid value for all chains -Doc-Content: https://wormhole.com/docs/products/queries/guides/verify-response/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- + --- -Doc-Content: https://wormhole.com/docs/products/queries/overview/ ---- BEGIN CONTENT --- ---- -title: Queries Overview -description: Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. -categories: Queries ---- + `EmitterChainID` ++"uint16"++ -# Queries Overview + Chain ID of the registered emitter. -Queries provide on-demand access to Guardian-attested on-chain data. They allow smart contracts to fetch real-time, verifiable data from across the multichain ecosystem, such as prices, rates, and liquidity. + --- -## Key Features + `EmitterAddress` ++"[32]uint8"++ -- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time -- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation -- **Cross-chain ready** – request data on one chain, use it on another -- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts -- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} + Address of the registered emitter, left-zero-padded if shorter than 32 bytes. -## How It Works +This payload can only be emitted by the Wormhole governance contract, ensuring that each chain accepts messages only from one verified bridge emitter per remote chain. -A query request follows a simple but robust lifecycle. The off-chain service responsible for handling requests is called the CCQ Server (Cross-Chain Query Server), also referred to as the Query Server throughout this documentation. +## UpgradeContract -1. An off-chain app sends a query to the CCQ Server via HTTPS -2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} -3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} independently fetch the data, verify it, and sign the result -4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response -5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data +The `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the Token Bridge contract on a specific chain. -The CCQ Server is permissioned but trustless. Most queries resolve in under one second, and Guardians retry failed requests for up to one minute. Up to 255 queries can be batched together to optimize performance, supporting efficient multichain workflows. +```text +Module [32]byte +Action uint8 = 2 +ChainId uint16 -![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp) +NewContract [32]uint8 +``` -## Use Cases +??? interface "Parameters" -Queries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them. + `Module` ++"[32]byte"++ -- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** + Module identifier, left-padded with `TokenBridge` for Token Bridge. - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + --- -- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** + `Action` ++"uint8"++ - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution - - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + Value must be `2`, indicating an `UpgradeContract` operation. -- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** + --- - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades + `ChainID` ++"uint16"++ -- **Multichain Prediction Markets** + The target chain where the governance action should be applied. - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution + --- -- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** + `NewContract` ++"[32]uint8"++ - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks + Address of the new Token Bridge contract, left-zero-padded to 32 bytes. -## Next Steps +This message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security. -Follow these steps to get started with Queries: +## Summary of Payload Structure -[timeline(wormhole-docs/.snippets/text/products/queries/queries-timeline.json)] +| Payload Type | ID | Purpose | Who Emits It | +|-----------------------|---------------|------------------------------------------------------------------------|------------------------| +| `Transfer` | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination | Token Bridge contract | +| `AssetMeta` | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer | Token Bridge contract | +| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution | Token Bridge contract | +| `RegisterChain` | Action `1` | Registers a verified Token Bridge emitter for a foreign chain | Wormhole governance | +| `UpgradeContract` | Action `2` | Upgrades the Token Bridge contract on a specific chain | Wormhole governance | --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-methods/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ --- BEGIN CONTENT --- --- -title: Queries Supported Methods -description: Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. -categories: Queries +title: Flow of a Token Bridge Transfer +description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. +categories: Token-Bridge, Transfer --- -# Supported Methods +# Flow of a Transfer -Wormhole Queries provides on-demand access to [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}-attested on-chain data through a simple REST endpoint. It offers a faster, gasless alternative to traditional transaction-based data retrieval, removing the need for gas fees and transaction finality delays. Requests are handled off-chain and processed by the Guardians, delivering verified data efficiently and cost-effectively. +## Introduction -This page describes Wormhole Queries, their functionality, and available methods, aiming to assist new developers in utilizing the service. +The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. -## Supported Query Types +This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. -Wormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains. +## Transfer Flow -!!! note - For a more comprehensive technical description and further specifics on each query type, please consult the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md). +Cross-chain token transfers using the Token Bridge follow these steps: +1. **Initiation on the Source Chain** + The transfer begins when a user calls the Token Bridge contract on the source chain: -### eth_call + - **Wrapped tokens**: The token is burned. + - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. -The [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank} query type allows you to perform read-only calls to a smart contract on a specific block, identified by its number or hash. Some of eth_call's configurations include: +2. **Transfer Message Publication** + The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. -- **Batching** - group multiple calls, even to different contracts, into a single query targeting the same block, which is processed as one batch RPC call to simplify on-chain verification -- **Capacity** - batch up to 255 individual in a single eth_call query -- **Result data** - provides the specified block's number, hash, timestamp, and the output from the contract call +3. **Message Observation and Signing** + [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. -### eth_call_by_timestamp + The VAA is then published to the Wormhole network. -The [`eth_call_by_timestamp`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#timestamp-and-block-id-hints-in-eth_call_by_timestamp){target=\_blank} query is similar to a standard `eth_call` but targets a specific timestamp instead of a block ID. This is useful for retrieving on-chain data based on a precise point in time, especially for correlating information across different chains. +4. **VAA Submission to the Destination Chain** + The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: -The query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block. + - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. + - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. -### eth_call_with_finality +5. **Finalization of the Transfer on the Destination Chain** + After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: -The [`eth_call_with_finality`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#desired-finality-in-eth_call_with_finality){target=\_blank} query type functions like a standard `eth_call`, but with an added critical assurance: it will only return the query results once the specified block has reached a designated level of finality on its chain. + - **Wrapped tokens**: A wrapped representation of the original token is minted. + - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. -You can specify one of two finality levels for your query: +Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. -- **Finalized** - indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain -- **Safe** - refers to a block considered highly unlikely to be reorganized, offering a substantial degree of confidence, though the network's consensus may not fully finalize it +```mermaid +sequenceDiagram + participant Alice as Alice + participant TokenBridgeEth as Token Bridge Ethereum
    (Source Chain) + participant CoreEth as Core Contract Ethereum
    (Source Chain) + participant Guardians + participant TokenBridgeSol as Token Bridge Solana
    (Destination Chain) + participant CoreSol as Core Contract Solana
    (Destination Chain) -!!! note - If the target blockchain does not natively support or recognize the safe finality tag, requesting safe finality will be treated as a request for finalized finality instead. + Alice->>TokenBridgeEth: Initiate ETH transfer
    (lock ETH) + TokenBridgeEth->>CoreEth: Publish transfer message + CoreEth-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA -### sol_account + alt Automatic VAA submission + Guardians->>TokenBridgeSol: Relayer submits VAA + else Manual VAA submission + Alice->>Guardians: Retrieve VAA + Alice->>TokenBridgeSol: Submit VAA + end -The [`sol_account`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana-queries){target=\_blank} query reads on-chain data for one or more specified accounts on the Solana blockchain. This functionality is similar to using Solana's native [`getMultipleAccounts`](https://solana.com/docs/rpc/http/getmultipleaccounts){target=\_blank} RPC method, enabling you to retrieve information for multiple accounts simultaneously + TokenBridgeSol->>CoreSol: Verify VAA + CoreSol-->>TokenBridgeSol: VAA verified + TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +``` -### sol_pda +Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. -The [`sol_pda`](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md#solana_queries){target=\_blank} query reads data for one or more Solana [Program Derived Addresses](https://www.anchor-lang.com/docs/pdas){target=\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data. +```mermaid +sequenceDiagram + participant User as Alice + participant TokenBridgeSrc as Token Bridge Solana
    (Source Chain) + participant CoreSrc as Core Contract Solana
    (Source Chain) + participant Guardians + participant TokenBridgeDst as Token Bridge Ethereum
    (Destination Chain) + participant CoreDst as Core Contract Ethereum
    (Destination Chain) -This is particularly useful for accessing multiple PDAs owned by a specific program or for verifying Solana PDA derivations on another blockchain, such as how associated token accounts are all derived from the [Associated Token Account Program](https://spl.solana.com/associated-token-account){target=\_blank}. ---- END CONTENT --- + User->>TokenBridgeSrc: Initiate transfer
    (burn wrapped ETH) + TokenBridgeSrc->>CoreSrc: Publish message + CoreSrc-->>Guardians: Emit message event + Guardians->>Guardians: Sign and publish VAA -Doc-Content: https://wormhole.com/docs/products/queries/reference/supported-networks/ ---- BEGIN CONTENT --- ---- -title: Queries Supported Networks -description: Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. -categories: Queries ---- + alt Automatic VAA submission + Guardians->>TokenBridgeDst: Relayer submits VAA + else Manual VAA submission + User->>Guardians: Retrieve VAA + User->>TokenBridgeDst: User submits VAA directly + end -# Supported Networks + TokenBridgeDst->>CoreDst: Verify VAA + CoreDst-->>TokenBridgeDst: VAA verified + TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) +``` -This page provides a quick reference for chains supported by Wormhole Queries, including each chain's Wormhole chain ID and the level of support for key methods: [`eth_call`](/docs/products/queries/reference/supported-methods/#eth_call){target=\_blank}, [`eth_call_by_timestamp`](/docs/products/queries/reference/supported-methods/#eth_call_by_timestamp){target=\_blank}, and [`eth_call_with_finality`](/docs/products/queries/reference/supported-methods/#eth_call_with_finality){target=\_blank}. -The **Expected History** column shows how much recent state data is typically available for querying, though this can vary depending on the chain and the configuration of each Guardian node. +## Automatic vs. Manual Transfers -The support shown in the table reflects what has been confirmed through testing. However, query success ultimately depends on whether the underlying call can be executed on each Guardian’s RPC node. +The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: -For example, many chains use a fork of [Geth](https://github.com/ethereum/go-ethereum){target=\_blank}, which by default retains 128 blocks of state in memory (unless archive mode is enabled). On Ethereum mainnet, this covers around 25 minutes of history—but on faster chains like Optimism, it may span only about three minutes. While Guardian nodes are expected to have access to recent state, there are currently no guarantees on how far back historical data is available. +- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. +- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. -## Mainnet +Here's a quick breakdown of the key differences: -| Chain | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History | -|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:| -| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks | -| BSC | 4 | ✅ | ✅ | ✅ | 128 blocks | -| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks | -| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks | -| Oasis Emerald | 7 | ✅ | ✅ | ✅ | archive | -| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks | -| Karura | 11 | ✅ | ✅ | ✅ | archive | -| Acala | 12 | ✅ | ✅ | ✅ | archive | -| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks | -| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks | -| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks | -| Arbitrum One | 23 | ✅ | ✅ | ✅ | ~6742 blocks | -| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks | -| Base | 30 | ✅ | ✅ | ✅ | archive | +| Feature | Automatic Transfer | Manual Transfer | +|---------------------------|-----------------------------|-------------------------------------| +| Who submits the VAA? | Relayer | User or dApp | +| User Experience | Seamless, one-step | Requires manual intervention | +| Best for | End-users, simple UIs | Custom dApps, advanced control | +| Dependency | Requires relayer support | None | -ℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains. +### Completing Manual Transfers + +The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. + +If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. + +## Token Bridge Relayer (TBR) + +When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. + + + +### Flow of an Automatic Transfer via TBR + +The flow of an automatic transfer using the TBR looks like this: + +1. **Initiation on the Source Chain** + The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + +2. **Prepare and Forward the Transfer** + The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. + +3. **Core Messaging Layer Processes the Transfer** + The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. + +4. **Off-Chain Relayer Observes the VAA** + + An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. + +5. **Relayer Computes Native Drop-Off and Submits the VAA** + + The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. + +6. **TBR Validates and Completes the Transfer** + + The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. + +6. **Asset Distribution on the Destination Chain** + + The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. + +The following diagram illustrates the key steps on the source chain during a transfer: + +```mermaid +sequenceDiagram + participant User + participant SourceTBR as Source Chain TBR + participant SourceTB as Source Chain Token Bridge + participant Messaging as Core Messaging Layer + + User->>SourceTBR: Initiate transfer (token,
    recipient, fees, native gas) + SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) + SourceTB->>Messaging: Publish transfer message +``` + +Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: + +```mermaid +sequenceDiagram + participant Messaging as Core Messaging Layer + participant Relayer as Off-chain Relayer + participant DestTBR as Destination Chain TBR + participant DestTB as Destination Chain
    Token Bridge + participant DestUser as User
    (Destination Chain) + + Messaging->>Relayer: Emit signed VAA for transfer + Relayer->>Relayer: Verifies destination chain and token registration + Relayer->>DestTBR: Query native gas amount + Relayer->>DestTBR: Submit signed VAA + DestTBR->>DestTB: Validate VAA + DestTBR->>DestTBR: Take custody of tokens + DestTBR->>DestUser: Send tokens (after fees & native gas) + DestTBR->>Relayer: Pay relayer fee & refund excess +``` + +## Next Steps + +Now that you’ve seen how a transfer works try both types yourself to experience the full process: + +- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/reference/chain-ids/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ --- BEGIN CONTENT --- --- -title: Chain IDs -description: This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. -categories: Reference +title: Token Bridge FAQs +description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. +categories: Token-Bridge, Transfer --- -# Chain IDs +# FAQs -The following table documents the chain IDs used by Wormhole and places them alongside the more commonly referenced [EVM Chain IDs](https://chainlist.org/){target=\_blank}. +## Can ownership of wrapped tokens be transferred from the Token Bridge? -!!! note - Please note, Wormhole chain IDs are different than the more commonly referenced EVM [chain IDs](https://eips.ethereum.org/EIPS/eip-155){target=\_blank}, specified in the Mainnet and Testnet ID columns. +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - - + - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself + - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge -=== "Mainnet" +The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. - | Ethereum | 2 | 1 | -| Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | -| Acala | 12 | 787 | -| Algorand | 8 | mainnet-v1.0 | -| Aptos | 22 | 1 | -| Arbitrum | 23 | Arbitrum One-42161 | -| Avalanche | 6 | C-Chain-43114 | -| Base | 30 | Base-8453 | -| Berachain | 39 | | -| Blast | 36 | 81457 | -| BNB Smart Chain | 4 | 56 | -| Celestia | 4004 | celestia | -| Celo | 14 | 42220 | -| Cosmos Hub | 4000 | cosmoshub-4 | -| Dymension | 4007 | dymension_1100-1 | -| Evmos | 4001 | evmos_9001-2 | -| Fantom | 10 | 250 | -| Gnosis | 25 | 100 | -| HyperEVM | 47 | | -| Injective | 19 | injective-1 | -| Ink | 46 | | -| Kaia | 13 | 8217 | -| Karura | 11 | 686 | -| Kujira | 4002 | kaiyo-1 | -| Linea | 38 | 59144 | -| Mantle | 35 | 5000 | -| Mezo | 50 | | -| Monad | 48 | | -| Moonbeam | 16 | 1284 | -| NEAR | 15 | mainnet | -| Neon | 17 | 245022934 | -| Neutron | 4003 | neutron-1 | -| Noble | 4009 | noble-1 | -| Oasis | 7 | 42262 | -| Optimism | 24 | 10 | -| Osmosis | 20 | osmosis-1 | -| Polygon | 5 | 137 | -| Provenance | 4008 | pio-mainnet-1 | -| Pythnet | 26 | | -| Scroll | 34 | 534352 | -| SEDA | 4006 | | -| Sei | 32 | pacific-1 | -| Seievm | 40 | | -| SNAXchain | 43 | 2192 | -| Sonic | 52 | 146 | -| Stargaze | 4005 | stargaze-1 | -| Sui | 21 | 35834a8a | -| Terra | 3 | columbus-5 | -| Terra 2.0 | 18 | phoenix-1 | -| Unichain | 44 | | -| World Chain | 45 | 480 | -| X Layer | 37 | 196 | -| XPLA | 28 | dimension_37-1 | +Relevant contracts: -=== "Testnet" + - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} + - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} + - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} - | Ethereum Holesky | 10006 | Holesky-17000 | -| Ethereum Sepolia | 10002 | Sepolia-11155111 | -| Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | -| Acala | 12 | 597 | -| Algorand | 8 | testnet-v1.0 | -| Aptos | 22 | 2 | -| Arbitrum Sepolia | 10003 | Sepolia-421614 | -| Avalanche | 6 | Fuji-43113 | -| Base Sepolia | 10004 | Base Sepolia-84532 | -| Berachain | 39 | 80084 | -| Blast | 36 | 168587773 | -| BNB Smart Chain | 4 | 97 | -| Celestia | 4004 | mocha-4 | -| Celo | 14 | Alfajores-44787 | -| Cosmos Hub | 4000 | theta-testnet-001 | -| Dymension | 4007 | | -| Evmos | 4001 | evmos_9000-4 | -| Fantom | 10 | 4002 | -| Gnosis | 25 | Chiado-10200 | -| HyperEVM | 47 | 998 | -| Injective | 19 | injective-888 | -| Ink | 46 | 763373 | -| Kaia | 13 | Kairos-1001 | -| Karura | 11 | 596 | -| Kujira | 4002 | harpoon-4 | -| Linea | 38 | 59141 | -| Mantle | 35 | Sepolia-5003 | -| Mezo | 50 | 31611 | -| Monad | 48 | 10143 | -| Moonbeam | 16 | Moonbase-Alphanet-1287 | -| NEAR | 15 | testnet | -| Neon | 17 | 245022940 | -| Neutron | 4003 | pion-1 | -| Noble | 4009 | grand-1 | -| Oasis | 7 | 42261 | -| Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | -| Osmosis | 20 | osmo-test-5 | -| Polygon Amoy | 10007 | Amoy-80002 | -| Provenance | 4008 | | -| Pythnet | 26 | | -| Scroll | 34 | Sepolia-534351 | -| SEDA | 4006 | seda-1-testnet | -| Sei | 32 | atlantic-2 | -| Seievm | 40 | | -| SNAXchain | 43 | 13001 | -| Sonic | 52 | 57054 | -| Stargaze | 4005 | | -| Sui | 21 | 4c78adac | -| Terra | 3 | bombay-12 | -| Terra 2.0 | 18 | pisco-1 | -| Unichain | 44 | Unichain Sepolia-1301 | -| World Chain | 45 | 4801 | -| X Layer | 37 | 195 | -| XPLA | 28 | cube_47-5 | - +## How do I update the metadata of a wrapped token? + +Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. + +## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? + +You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. + +## How can I update my wrapped token image on Solscan? + +Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. + +To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/reference/consistency-levels/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/get-started/ --- BEGIN CONTENT --- --- -title: Wormhole Finality | Consistency Levels -description: This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. -categories: Reference +title: Get Started with Token Bridge +description: Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). +categories: Token-Bridge, Transfers --- -# Wormhole Finality +# Get Started with Token Bridge -The following table documents each chain's `consistencyLevel` values (i.e., finality reached before signing). The consistency level defines how long the Guardians should wait before signing a VAA. The finalization time depends on the specific chain's consensus mechanism. The consistency level is a `u8`, so any single byte may be used. However, a small subset has particular meanings. If the `consistencyLevel` isn't one of those specific values, the `Otherwise` column describes how it's interpreted. +## Introduction - - -| Ethereum | 200 | 201 | | finalized | ~ 19min | Details | -| Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | -| Algorand | | | 0 | | ~ 4s | Details | -| Aptos | | | 0 | | ~ 4s | Details | -| Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | -| Avalanche | 200 | | | finalized | ~ 2s | Details | -| Base | 200 | 201 | | finalized | ~ 18min | | -| Berachain | 200 | | | finalized | ~ 4s | | -| Blast | 200 | 201 | | finalized | ~ 18min | | -| BNB Smart Chain | 200 | 201 | | finalized | ~ 48s | Details | -| Celestia | | | 0 | | ~ 5s | | -| Celo | 200 | | | finalized | ~ 10s | | -| Cosmos Hub | | | 0 | | ~ 5s | | -| Dymension | | | 0 | | ~ 5s | | -| Evmos | | | 0 | | ~ 2s | | -| Fantom | 200 | | | finalized | ~ 5s | | -| Injective | | | 0 | | ~ 3s | | -| Ink | | | 0 | | ~ 9min | | -| Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | -| Kujira | | | 0 | | ~ 3s | | -| Mantle | 200 | 201 | | finalized | ~ 18min | | -| Mezo | | | 0 | | ~ 8s | | -| Monad | | | 0 | | ~ 2s | | -| Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | -| NEAR | | | 0 | | ~ 2s | Details | -| Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | -| Optimism | 200 | 201 | | finalized | ~ 18min | | -| Osmosis | | | 0 | | ~ 6s | | -| Polygon | 200 | | | finalized | ~ 66s | Details | -| Scroll | 200 | | | finalized | ~ 16min | | -| Sei | | | 0 | | ~ 1s | | -| Sonic | | | 0 | | ~ 1s | | -| Stargaze | | | 0 | | ~ 5s | | -| Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | -| Terra 2.0 | | | 0 | | ~ 6s | | -| Unichain | 200 | 201 | | finalized | ~ 18min | | -| World Chain | | | 0 | | ~ 18min | | -| X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | - ---- END CONTENT --- +Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. -Doc-Content: https://wormhole.com/docs/products/reference/contract-addresses/ ---- BEGIN CONTENT --- ---- -title: Contract Addresses -description: This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. -categories: Reference ---- +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. -# Contract Addresses + - **Manual transfer** – where you control each step + - **Automatic transfer** – where a relayer finalizes the transfer for you -## Core Contracts +These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. - - +## Prerequisites -=== "Mainnet" +Before you begin, make sure you have the following: - | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | -| Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Algorand | 842125965 | -| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | -| Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | -| Avalanche | 0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c | -| Base | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Berachain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| Blast | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| BNB Smart Chain | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | -| Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | -| Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | -| NEAR | contract.wormhole_crypto.near | -| Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | -| Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | -| Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | -| Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | -| Scroll | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sei | sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn | -| Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | -| Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | -| Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | -| Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | -| World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | -| X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} + - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -=== "Testnet" +This guide uses a Solana wallet with [devnet SOL](https://faucet.solana.com/){target=\_blank} and an EVM wallet with [Sepolia ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank} for the manual transfer example, and [Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains. - | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | -| Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | -| Algorand | 86525623 | -| Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | -| Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | -| Avalanche | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | -| Base Sepolia | 0x79A1027a6A159502049F10906D333EC57E95F083 | -| Berachain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Blast | 0x473e002D7add6fB67a4964F13bFd61280Ca46886 | -| BNB Smart Chain | 0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D | -| Celo | 0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56 | -| Fantom | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | -| Gnosis | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| HyperEVM | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | -| Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | -| Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | -| Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | -| Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | -| Monad | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Moonbeam | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | -| NEAR | wormhole.wormhole.testnet | -| Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | -| Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | -| Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | -| Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | -| Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | -| Pythnet | EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z | -| Scroll | 0x055F47F1250012C6B20c436570a76e52c17Af2D5 | -| Sei | sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s | -| Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | -| Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | -| Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | -| World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | -| X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | +## Configure Your Token Transfer Environment -=== "Devnet" +1. Create a new directory and initialize a Node.js project: - | Ethereum | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | -| Solana | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | -| Algorand | 1004 | -| Aptos | 0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017 | -| BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | -| NEAR | wormhole.test.near | -| Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | -| Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | - + ```bash + mkdir token-bridge + cd token-bridge + npm init -y + ``` -## Token Bridge +2. Install the required dependencies: - - + ```bash + npm install @wormhole-foundation/sdk + npm install -D tsx typescript + ``` -=== "Mainnet" +3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities: - | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | -| Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | -| Algorand | 842126029 | -| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | -| Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | -| Avalanche | 0x0e082F06FF657D94310cB8cE8B0D9a04541d8052 | -| Base | 0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627 | -| Berachain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| Blast | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| BNB Smart Chain | 0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7 | -| Celo | 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed | -| Fantom | 0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2 | -| Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | -| Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | -| Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | -| NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | -| Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | -| Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | -| Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | -| Sei | sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3 | -| Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | -| Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | -| Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | -| Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | -| World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | -| X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | + ```bash + touch transfer.ts helper.ts + ``` -=== "Testnet" +4. Set up secure access to your wallets. This guide assumes you are loading your `SOL_PRIVATE_KEY` and `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. - | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | -| Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | -| Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | -| Algorand | 86525641 | -| Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | -| Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Avalanche | 0x61E44E506Ca5659E6c0bba9b678586fA2d729756 | -| Base Sepolia | 0x86F55A04690fd7815A3D802bD587e83eA888B239 | -| Berachain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Blast | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | -| BNB Smart Chain | 0x9dcF9D205C9De35334D646BeE44b2D2859712A09 | -| Celo | 0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153 | -| Fantom | 0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8 | -| HyperEVM | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | -| Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | -| Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | -| Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | -| Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | -| Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| Monad | 0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659 | -| Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | -| NEAR | token.wormhole.testnet | -| Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | -| Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | -| Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | -| Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | -| Sei | sei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2 | -| Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | -| SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | -| Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | -| Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | -| World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | -| X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | + !!! warning + If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. -=== "Devnet" +## Perform a Token Transfer - | Ethereum | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | -| Solana | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | -| Algorand | 1006 | -| Aptos | 0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31 | -| BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | -| NEAR | token.test.near | -| Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | -| Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | - +This section shows how to run manual and automatic token transfers using a shared project structure. You will define helper utilities once and reuse them across both flows. -## Wormhole Relayer +In the manual transfer, you initiate a transfer on Solana, wait for Guardian signatures, and redeem the tokens on Sepolia, giving you complete control over each step. In the automatic transfer, the relayer handles attestation and redemption, simplifying the process between EVM chains. - - +1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed: -=== "Mainnet" + ```ts title="helper.ts" + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + isTokenId, + TokenId, +} from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; - | Ethereum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Arbitrum | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Avalanche | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Base | 0x706f82e9bb5b0813501714ab5974216704980e31 | -| Berachain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Blast | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| BNB Smart Chain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Celo | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Fantom | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Ink | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Kaia | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Mantle | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Moonbeam | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | -| World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | -| X Layer | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must + * be loaded securely beforehand, for example via a keystore, secrets + * manager, or environment variables (not recommended). + */ +export async function getSigner( + chain: ChainContext +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; -=== "Testnet" + switch (platform) { + case 'Evm': + signer = await ( + await evm() + ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); + break; + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); + break; + default: + throw new Error(`Unsupported platform: ${platform}`); + } - | Ethereum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Arbitrum Sepolia | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Avalanche | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB | -| Base Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Berachain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| BNB Smart Chain | 0x80aC94316391752A193C1c47E27D382b507c93F3 | -| Celo | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 | -| Fantom | 0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470 | -| Ink | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | -| Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | -| Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | -| Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} -=== "Devnet" +/** + * Get the number of decimals for the token on the source chain. + * This helps convert a user-friendly amount (e.g., '1') into raw units. + */ +export async function getTokenDecimals( + wh: Wormhole, + token: TokenId, + chain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : chain.config.nativeTokenDecimals; +} + + ``` - | Ethereum | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | -| BNB Smart Chain | 0xcC680D088586c09c3E0E099a676FA4b6e42467b4 | - +2. In `transfer.ts`, add the script for your preferred transfer mode. The `automatic` flag controls transfer behavior passed to `tokenTransfer()`; set it to `false` for manual transfers and `true` for automatic transfers -## CCTP + === "Manual Transfer" - - + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; -=== "Mainnet" +(async function () { + // Initialize Wormhole SDK for Solana and Sepolia on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); - | Ethereum | 0xAaDA05BD399372f0b0463744C09113c137636f6a | -| Arbitrum | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x09Fb06A271faFf70A651047395AaEb6265265F13 | -| Base | 0x03faBB06Fa052557143dC28eFCFc63FC12843f1D | -| Optimism | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Polygon | 0x0FF28217dCc90372345954563486528aa865cDd6 | + // Define the source and destination chains + const sendChain = wh.getChain('Solana'); + const rcvChain = wh.getChain('Sepolia'); -=== "Testnet" + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - | Ethereum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Arbitrum Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Avalanche | 0x58f4c17449c90665891c42e14d34aae7a26a472e | -| Base Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | -| Optimism Sepolia | 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c | + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Solana', 'native'); + const amt = '0.1'; -=== "Devnet" + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); - N/A - - + // Set to false to require manual approval steps + const automatic = false; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; -## Settlement Token Router + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); -=== "Mainnet" + // Initiate the transfer from Solana + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | + // Wait for the signed attestation from the Guardian network + console.log('Fetching Attestation'); + const timeout = 5 * 60 * 1000; // 5 minutes + await xfer.fetchAttestation(timeout); -=== "Testnet" + // Redeem the tokens on Sepolia + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(destination.signer); + console.log(`Completed Transfer: `, destTxids); - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | + process.exit(0); +})(); + ``` + === "Automatic Transfer" -## Read-Only Deployments - -=== "Mainnet" + ```ts title="transfer.ts" + import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import evm from '@wormhole-foundation/sdk/evm'; +import { getSigner, getTokenDecimals } from './helper'; - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | -| Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | -| Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | -| Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | -| Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +(async function () { + // Initialize Wormhole SDK for Avalanche and Celo on Testnet + const wh = await wormhole('Testnet', [solana, sui, evm]); -!!!note - Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. ---- END CONTENT --- + // Define the source and destination chains + const sendChain = wh.getChain('Avalanche'); + const rcvChain = wh.getChain('Celo'); -Doc-Content: https://wormhole.com/docs/products/reference/supported-networks/ ---- BEGIN CONTENT --- ---- -title: Supported Networks -description: Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. -categories: Reference ---- + // Load signers and addresses from helpers + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -# Supported Networks + // Define the token and amount to transfer + const tokenId = Wormhole.tokenId('Avalanche', 'native'); + const amt = '0.2'; -Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. + // Convert to raw units based on token decimals + const decimals = await getTokenDecimals(wh, tokenId, sendChain); + const transferAmount = amount.units(amount.parse(amt, decimals)); -## Networks - - - -
    + // Set to false to require manual approval steps + const automatic = true; + const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; -### Connect + // Construct the transfer object + const xfer = await wh.tokenTransfer( + tokenId, + transferAmount, + source.address, + destination.address, + automatic, + undefined, + nativeGas + ); -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Osmosis | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
    - - -
    + // Initiate the transfer from Avalanche Fuji + console.log('Starting Transfer'); + const srcTxids = await xfer.initiateTransfer(source.signer); + console.log(`Started Transfer: `, srcTxids); -### NTT + process.exit(0); +})(); + ``` -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
    - - -
    -### Token Bridge +3. Execute the script to initiate and complete the transfer: -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | -| Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
    - - -
    + ```bash + npx tsx transfer.ts + ``` -### CCTP + If successful, the expected output should be similar to this: -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | +
    +npx tsx transfer.ts +Starting Transfer +Started Transfer: ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB'] + +Getting Attestation +Retrying Wormholescan:GetVaaBytes, attempt 0/900 +Retrying Wormholescan:GetVaaBytes, attempt 1/900 +Retrying Wormholescan:GetVaaBytes, attempt 2/900 + +Completing Transfer +Completed Transfer: [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ] +
    - - -
    -### Settlement +To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. -| Ethereum | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Solana | SVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sui | Sui Move VM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
    - - -
    +## Next Steps -### MultiGov +Now that you've completed a manual multichain token transfer, explore these guides to continue building: -| Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Berachain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Blast | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| BNB Smart Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Celo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Fantom | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Gnosis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | -| Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sei | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Seievm | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | | -| SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Sonic | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Unichain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| World Chain | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| X Layer | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -
    + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/reference/testnet-faucets/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/token-bridge-contracts/ --- BEGIN CONTENT --- --- -title: Testnet Faucets -description: This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. -categories: Reference +title: Get Started with Token Bridge +description: Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. +categories: Token-Bridge, Transfer --- -# Testnet Faucets +# Interact with Token Bridge Contracts -## Get Started +## Introduction -Don't let the need for testnet tokens get in the way of buildling your next great idea with Wormhole. Use this guide to quickly locate the testnet token faucets you need to deploy and test applications and contracts on Wormhole's supported networks. +Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. - - -
    +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. -### EVM +## Prerequisites -| Ethereum Holesky | EVM | ETH | Alchemy Faucet | -| Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | -| Arbitrum Sepolia | EVM | ETH | List of Faucets | -| Avalanche | EVM | AVAX | Official Avalanche Faucet | -| Base Sepolia | EVM | ETH | List of Faucets | -| Berachain | EVM | BERA | Official Berachain Faucet | -| Blast | EVM | ETH | List of Faucets | -| BNB Smart Chain | EVM | BNB | Official BNB Faucet | -| Celo | EVM | CELO | Official Celo Faucet | -| Fantom | EVM | FTM | Official Fantom Faucet | -| Gnosis | EVM | xDAI | Official Gnosis Faucet | -| HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | -| Ink | EVM | ETH | Official Ink Faucet | -| Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | -| Linea | EVM | ETH | List of Faucets | -| Mantle | EVM | MNT | Official Mantle Faucet | -| Monad | EVM | MON | Official Monad Faucet | -| Moonbeam | EVM | DEV | Official Moonbeam Faucet | -| Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | -| Optimism Sepolia | EVM | ETH | Superchain Faucet | -| Polygon Amoy | EVM | POL | Official Polygon Faucet | -| Scroll | EVM | ETH | List of Faucets | -| Unichain | EVM | ETH | QuickNode Faucet | -| World Chain | EVM | ETH | Alchemy Faucet | -| X Layer | EVM | OKB | X Layer Official Faucet | +To interact with the Wormhole Token Bridge, you'll need the following: -### SVM +- [The address of the Token Bridge contract](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} on the chains you're working with +- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\_blank} of the chains you're targeting for token transfers -| Pythnet | SVM | ETH | Superchain Faucet | +## How to Interact with Token Bridge Contracts -### AVM +The primary functions of the Token Bridge contracts revolve around: -| Algorand | AVM | ALGO | Official Algorand Faucet | +- **Attesting a token** - registering a new token for cross-chain transfers +- **Transferring tokens** - locking and minting tokens across chains +- **Transferring tokens with a payload** - including additional data with transfers -### CosmWasm +### Attest a token -| Celestia | CosmWasm | TIA | Discord Faucet | -| Cosmos Hub | CosmWasm | ATOM | Discord Faucet | -| Evmos | CosmWasm | TEVMOS | Official Evmos Faucet | -| Injective | CosmWasm | INJ | Official Injective Faucet | -| Kujira | CosmWasm | KUJI | Discord Faucet | -| Neutron | CosmWasm | NTRN | List of Faucets | -| Noble | CosmWasm | USDC | Circle Faucet | -| Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | -| SEDA | CosmWasm | SEDA | Official SEDA Faucet | -| Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | -| Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | +Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. -### Move VM +The attestation process doesn't require you to manually input token details like name, symbol, or decimals. Instead, the Token Bridge contract retrieves these values from the token contract itself when you call the `attestToken()` method. -| Aptos | Move VM | APT | Official Aptos Faucet | +```solidity +function attestToken( + address tokenAddress, + uint32 nonce +) external payable returns (uint64 sequence); +``` -### NEAR VM +??? interface "Parameters" -| NEAR | NEAR VM | NEAR | Official NEAR Faucet | + `tokenAddress` ++"address"++ + + The contract address of the token to be attested. -### Sui Move VM + --- -| Sui | Sui Move VM | SUI | List of Faucets | -
    - ---- END CONTENT --- + `nonce` ++"uint32"++ -Doc-Content: https://wormhole.com/docs/products/reference/wormhole-formatted-addresses/ ---- BEGIN CONTENT --- ---- -title: Wormhole Formatted Addresses -description: Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. -categories: Reference ---- + An arbitrary value provided by the caller to ensure uniqueness. -# Wormhole Formatted Addresses +??? interface "Returns" -## Introduction + `sequence` ++"uint64"++ + + A unique identifier for the attestation transaction. -Wormhole formatted addresses are 32-byte hex representations of addresses from any supported blockchain. Whether an address originates from EVM, Solana, Cosmos, or another ecosystem, Wormhole standardizes all addresses into this format to ensure cross-chain compatibility. +When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. -This uniform format is essential for smooth interoperability in token transfers and messaging across chains. Wormhole uses formatted addresses throughout the [Wormhole SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank}, especially in cross-chain transactions, such as transfer functions that utilize the `bytes32` representation for recipient addresses. +You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. -## Platform-Specific Address Formats +### Transfer Tokens -Each blockchain ecosystem Wormhole supports has its method for formatting native addresses. To enable cross-chain compatibility, Wormhole converts these native addresses into the standardized 32-byte hex format. +Once a token is attested, a cross-chain token transfer can be initiated following the lock-and-mint mechanism. On the source chain, tokens are locked (or burned if they're already a wrapped asset), and a VAA is emitted. On the destination chain, that VAA is used to mint or release the corresponding amount of wrapped tokens. -Here’s an overview of the native address formats and how they are normalized to the Wormhole format: +Call `transferTokens()` to lock/burn tokens and produce a VAA with transfer details. -| Platform | Native Address Format | Wormhole Formatted Address | -|-----------------|----------------------------------|----------------------------| -| EVM | Hex (e.g., 0x...) | 32-byte Hex | -| Solana | Base58 | 32-byte Hex | -| CosmWasm | Bech32 | 32-byte Hex | -| Algorand | Algorand App ID | 32-byte Hex | -| Sui | Hex | 32-byte Hex | -| Aptos | Hex | 32-byte Hex | -| Near | SHA-256 | 32-byte Hex | +```solidity +function transferTokens( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint256 arbiterFee, + uint32 nonce +) external payable returns (uint64 sequence); +``` -These conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses. +??? interface "Parameters" -### Address Format Handling + `token` ++"address"++ + + The address of the token being transferred. -The Wormhole SDK provides mappings that associate each platform with its native address format. You can find this mapping in the Wormhole SDK file [`platforms.ts`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/base/src/constants/platforms.ts#L93-L102){target=\_blank}: + --- -```typescript -const platformAddressFormatEntries = [ - ['Evm', 'hex'], - ['Solana', 'base58'], - ['Cosmwasm', 'bech32'], - ['Algorand', 'algorandAppId'], - ['Sui', 'hex'], - ['Aptos', 'hex'], - ['Near', 'sha256'], -]; -``` + `amount` ++"uint256"++ + The amount of tokens to be transferred. -These entries define how the [`UniversalAddress`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/007f61b27c650c1cf0fada2436f79940dfa4f211/core/definitions/src/universalAddress.ts#L23){target=\_blank} class handles different address formats based on the platform. + --- -## Universal Address Methods + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -The `UniversalAddress` class is essential for working with Wormhole formatted addresses. It converts native blockchain addresses into the standardized 32-byte hex format used across Wormhole operations. + --- -Key functions: + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. - - **`new UniversalAddress()`** - use the `UniversalAddress` constructor to convert native addresses into the Wormhole format + --- - ```typescript - const universalAddress = new UniversalAddress('0x123...', 'hex'); - ``` + `arbiterFee` ++"uint256"++ + Optional fee to be paid to an arbiter for relaying the transfer. - - **`toUniversalAddress()`** - converts a platform-specific address into the Wormhole formatted 32-byte hex address + --- - ```typescript - const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...'); - const universalAddress = ethAddress.toUniversalAddress().toString(); - ``` + `nonce` ++"uint32"++ + A unique identifier for the transaction. - - **`toNative()`** - converts the Wormhole formatted address back to a native address for a specific blockchain platform +??? interface "Returns" - ```typescript - const nativeAddress = universalAddress.toNative('Evm'); - ``` + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. - - **`toString()`** - returns the Wormhole formatted address as a hex string, which can be used in various SDK operations +Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. - ```typescript - console.log(universalAddress.toString()); - ``` +```solidity +function completeTransfer(bytes memory encodedVm) external; +``` -These methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility. +??? interface "Parameters" -## Convert Between Native and Wormhole Formatted Addresses + `encodedVm` ++"bytes memory"++ + + The signed VAA containing the transfer details. -The Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications. +!!!note + - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation + - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -### Convert a Native Address to a Wormhole Formatted Address +### Transfer tokens with payload -Example conversions for EVM and Solana: +While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. -=== "EVM" +Call `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer. - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; +```solidity +function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload +) external payable returns (uint64 sequence); +``` -const ethAddress: NativeAddress<'Evm'> = toNative( - 'Ethereum', - '0x0C99567DC6f8f1864cafb580797b4B56944EEd28' -); -const universalAddress = ethAddress.toUniversalAddress().toString(); -console.log('Universal Address (EVM):', universalAddress); - ``` +??? interface "Parameters" -=== "Solana" + `token` ++"address"++ + + The address of the token being transferred. - ```typescript - import { toNative } from '@wormhole-foundation/sdk-core'; + --- -const solAddress: NativeAddress<'Solana'> = toNative( - 'Solana', - '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J' -); -const universalAddressSol = solAddress.toUniversalAddress().toString(); -console.log('Universal Address (Solana):', universalAddressSol); - ``` + `amount` ++"uint256"++ + The amount of tokens to be transferred. -The result is a standardized address format that is ready for cross-chain operations. + --- -### Convert Back to Native Addresses + `recipientChain` ++"uint16"++ + The Wormhole chain ID of the destination chain. -Below is how you can convert a Wormhole formatted address back to an EVM or Solana native address: + --- -```typescript -const nativeAddressEvm = universalAddress.toNative('Evm'); -console.log('EVM Native Address:', nativeAddressEvm); + `recipient` ++"bytes32"++ + The recipient's address on the destination chain. -const nativeAddressSolana = universalAddress.toNative('Solana'); -console.log('Solana Native Address:', nativeAddressSolana); -``` + --- -These conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems. + `nonce` ++"uint32"++ + A unique identifier for the transaction. -## Use Cases for Wormhole Formatted Addresses + --- -### Cross-chain Token Transfers + `payload` ++"bytes memory"++ + Arbitrary data payload attached to the transaction. -Cross-chain token transfers require addresses to be converted into a standard format. For example, when transferring tokens from Ethereum to Solana, the Ethereum address is converted into a Wormhole formatted address to ensure compatibility. After the transfer, the Wormhole formatted address is converted back into the Solana native format. +??? interface "Returns" + + `sequence` ++"uint64"++ + + A unique identifier for the transfer transaction. -### Smart Contract Interactions +After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. -In smart contract interactions, especially when building dApps that communicate across multiple chains, Wormhole formatted addresses provide a uniform way to reference addresses. This ensures that addresses from different blockchains can interact seamlessly, whether you're sending messages or making cross-chain contract calls. +Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. -### DApp Development +```solidity +function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); +``` -For cross-chain dApp development, Wormhole formatted addresses simplify handling user wallet addresses across various blockchains. This allows developers to manage addresses consistently, regardless of whether they work with EVM, Solana, or another supported platform. +??? interface "Parameters" -### Relayers and Infrastructure + `encodedVm` ++"bytes memory"++ -Finally, relayers and infrastructure components, such as Wormhole Guardians, rely on the standardized format to efficiently process and relay cross-chain messages. A uniform address format simplifies operations, ensuring smooth interoperability across multiple blockchains. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/concepts/architecture/ ---- BEGIN CONTENT --- ---- -title: Settlement Protocol Architecture -description: Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. -categories: Settlement, Transfer ---- - -# Settlement Protocol Architecture - -## Introduction - -This page describes the high-level mechanics of the underlying native swap protocols in the Wormhole SDK. While built on Wormhole messaging, each protocol uses a novel architecture with unique price discovery, scalability, and latency tradeoffs. These designs enable redundancy to handle highly asymmetric flows and sharp volume changes. These sections will cover the following: - -- **Wormhole Liquidity Layer** - a cross-chain transfer protocol that utilizes Solana as the central orchestration layer for cross-chain intents, allowing solvers to deploy liquidity from a single Solana-based hub rather than distributing it across each supported chain -- **Mayan Swift** - a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent -- **Mayan MCTP** - a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains - -## Wormhole Liquidity Layer - -Wormhole Liquidity Layer is a cross-chain transfer protocol that enables faster-than-finality transfers across the Wormhole ecosystem through a novel, Solana-based hub-and-spoke architecture. The hub-and-spoke model leverages interoperable token standards like Circle's CCTP (and Wormhole's NTT), allowing the solver to natively mint and burn assets between chains for intent fulfillment. This architecture allows solvers to facilitate cross-chain transfers by fronting assets on the destination chain and assuming the finality risk of the originating source chain transaction. - -Solvers concentrate their liquidity entirely on Solana, where they participate in permissionless on-chain English auctions (open ascending-price auctions where bidders publicly raise bids until only one bidder remains) to fulfill each cross-chain transfer. Upon the conclusion of each auction, the winning solver initiates a transfer from Solana to the specified destination chain. The solver rebalances inventory once the originating source chain transaction reaches finality and arrives to Solana. + The signed VAA containing the transfer details. -![Wormhole Settlments Liquidity layer architecture diagram: source chain to hub to destination chain](/docs/images/products/settlement/concepts/architecture/architecture-1.webp) +??? interface "Returns" -The Wormhole Liquidity Layer serves as the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems by enabling protocols to bundle call data containing arbitrary protocol actions, which can be executed atomically alongside each transfer. This feature allows developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. + `bytes memory` -### Solvers and Liquidity Fragmentation + The extracted payload data. -Traditional intent-based protocols require solvers to distribute their capital across each supported chain in the network. This liquidity fragmentation leads to capital inefficiency and requires complex rebalancing to manage asymmetric flows between chains. As the number of chains increases, solvers face scalability challenges, which can result in market concentration, reducing competition and potentially impacting price discovery in intent execution. +## Source Code References -Using a hub-and-spoke model, the Wormhole Liquidity Layer solves these challenges by consolidating solver liquidity on a single chain, Solana. This model eliminates the need for complex cross-chain rebalancing and simplifies solvers' infrastructure requirements. Solvers only need to consider the finality risk of the originating source chain transaction and the payload size when bidding on transfers. By concentrating liquidity on Solana, the protocol can handle large transfer volumes with a smaller capital base, enhancing capital efficiency and lowering barriers to entry for solvers. This approach promotes competition, improves overall market efficiency, and ultimately benefits users with better prices while still preserving the speed of transactions. +For a deeper understanding of the Token Bridge implementation and to review the actual source code, please refer to the following links: -### Enable Unified Liquidity +- [Token Bridge contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\_blank} +- [Token Bridge interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} -The novel hub-and-spoke liquidity architecture relies on interoperable token standards that enable cross-chain token fungibility, such as Circle's Cross-Chain Transfer Protocol (CCTP) and Wormhole's Native Token Transfers (NTT). These protocols allow assets to move seamlessly between chains, making unified liquidity possible. On the liquidity hub (Solana), solvers concentrate their liquidity in NTT or CCTP-supported assets, such as USDC. These assets act as the shuttle between chains but may not necessarily be the user's original or final asset. +## Portal Bridge -After the Solana auction concludes, the appropriate instructions are called on the CCTP or NTT contract, initiating the transfer from Solana to the destination chain by burning/locking the asset on Solana and sequentially minting on the destination chain. Solvers rebalance their inventory on Solana using these interoperable token standards as well. Once the originating source chain transaction reaches finality and arrives to Solana, the solver can redeem the NTT or CCTP message, minting the inventory for use once again. +A practical implementation of the Wormhole Token Bridge can be seen in [Portal Bridge](https://portalbridge.com/){target=\_blank}, which provides an easy-to-use interface for transferring tokens across multiple blockchain networks. It leverages the Wormhole infrastructure to handle cross-chain asset transfers seamlessly, offering users a convenient way to bridge their assets while ensuring security and maintaining token integrity. +--- END CONTENT --- -By leveraging interoperable token standards like NTT, this model of liquidity facilitation for cross-chain intents can arbitrarily scale to any chain or ecosystem while preserving fully unified liquidity. This removes the need for solver "buy-in" when expanding to new chains. Additionally, regardless of proven traction, new chains can access the same level of liquidity for cross-chain intent fulfillment from the first day of mainnet launch as long-standing ecosystems with clear evidence of adoption. This is often overlooked by solvers, who must aggressively prioritize high-flow chains due to high opportunity costs. The model also supports ecosystems without Centralized Exchange (CEX) enabled withdrawals. +Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ +--- BEGIN CONTENT --- +--- +title: Token Bridge Overview +description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. +categories: Token-Bridge, Transfer +--- -### Protocol Flow: How It Works +# Token Bridge Overview -1. **Initiation** - users or protocols initiate a transfer via an interface or directly on-chain. They choose between a standard transfer (waiting for finality on the sending chain) or a fast transfer (triggering the auction process). For fast transfers, users or the protocol specify a maximum fee and an auction start deadline +The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. - !!! Note - If an auction doesn't start within the set deadline, a standard transfer will proceed directly from the source to the destination chain. +This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. -2. **Auction** - solvers monitor the Wormhole network for these fast transfer requests and initiate an auction on Solana by offering to fulfill the transfer at or below the user's maximum fee. To start the auction, the solver must transfer the requested funds plus a small security deposit to the Matching Engine contract -3. **Competition** - once initiated, other solvers can participate by submitting lower bids in a simple English auction, aiming to provide users with the best rate. If a new solver submits a better offer, the previous solver's funds and security deposit are returned, with the latest offer taking precedence atomically. This competition ensures that users receive the best possible transfer rate -4. **Fulfillment** - after the auction concludes, the winning solver must complete the transfer within a predefined grace period to earn their fee and reclaim their security deposit. Failure to do so may result in the security deposit being slashed, with the slashed amount compensating the user for delays. This mechanism incentivizes prompt execution. Upon successful completion, the Fast Transfer hub sends the USDC to the user's destination wallet, and the solver receives their security deposit and transfer fee -5. **Settlement** - once the source chain transaction reaches finality, the winning solver can use the finalized Wormhole message to settle the auction with the matching engine and rebalance. This allows the solver to retrieve the original transfer amount into their wallet +## Key Features -## Mayan Swift +Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -Mayan Swift is a flexible cross-chain intent protocol that embeds a competitive on-chain price auction to determine the best possible execution for the expressed user intent. +- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain +- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains +- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions +- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity -### On-Chain Competitive Price Discovery Mechanism +## How It Works -Traditional intent-based protocols essentially function as cross-chain limit orders. If the order is profitable, solvers will compete to fulfill it, leading to MEV-like competition focused on speed. While functional, this methodology presents two clear inefficiencies and drawbacks. +The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -First, they lack a competitive price discovery mechanism as limit order prices are typically determined through centralized off-chain systems. Second, in this MEV-like market structure, only a single solver can win, while the others lose out on transaction fees. This dynamic of deadweight loss results in solvers prioritizing high-margin orders, ultimately resulting in elevated fees for end-users without commensurate benefits. +1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token +2. **Locking** - on the source chain, the native token is locked in a custody account +3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} +4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity +5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain -Mayan Swift addresses these limitations by implementing competitive on-chain English auctions on Solana as an embedded price discovery mechanism, fundamentally shifting solver competition from speed-based to price-based execution. Through this architecture, the solver offering the best possible price secures the right to fulfill the order within pre-specified deadline parameters. +This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. -![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp) +```mermaid +sequenceDiagram + participant Alice + participant Ethereum + participant GuardianNetwork + participant Solana -### Protocol Flow: How It Works + Alice->>Ethereum: Lock ETH in Token Bridge contract + Ethereum->>GuardianNetwork: Emit transfer message + GuardianNetwork->>GuardianNetwork: Verify and sign message -1. **Initiation** - the user creates an order by signing a transaction that locks one of the primary assets (USDC or ETH) into the Mayan smart contract, specifying the desired outcome. + GuardianNetwork->>Solana: Submit signed message + Solana->>Solana: Verify message and mint wrapped ETH (WETH) - !!!note - If the input asset is not a primary asset, it is converted into a primary asset within the same transaction before the order is submitted. + Solana->>Alice: Deliver wrapped ETH on Solana +``` - Each order includes properties such as destination chain, destination wallet address, output token address, minimum output amount, gas drop amount, deadline, and 32 bytes of random hex to prevent collisions. A Keccak-256 hash is then calculated to identify the order +For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. -2. **Auction** - solvers observe on-chain data or subscribe to the Mayan explorer web socket (solvers using the Mayan explorer verify the order's integrity by checking the data against the on-chain hash). Once the new order is verified, an on-chain auction on Solana is initiated by passing the order ID and the bid amount, which cannot be lower than the minimum amount. Other solvers can increase the bid by submitting a higher amount before the auction ends -3. **Fulfillment** - the auction ends three seconds after the initial bid. Once the auction ends, the winning solver can execute an instruction that passes their wallet address on the destination chain. This triggers a Wormhole message containing the order ID and the winner's wallet address. Wormhole Guardians then sign this message, allowing the winning solver to fulfill the order on the destination chain by submitting proof of their win and the promised amount to the Mayan contract before the deadline. The Mayan contract deducts a protocol fee (currently 3 basis points) and a referral fee (if applicable), transferring the remaining amount to the user's destination wallet. It also triggers a Wormhole message as proof of fulfillment -4. **Settlement** - after the Wormhole Guardians sign the fulfillment message, the winning solver can submit this message on the source chain to unlock the user's funds and transfer them to their own wallet. Upon fulfillment, the solver has the option to delay triggering a Wormhole message immediately. Instead, they can batch the proofs and, once the batch reaches a certain threshold, issue a batched proof to unlock all orders simultaneously, saving on gas fees +## Use Cases -## Mayan MCTP +Here are key use cases that highlight the power and versatility of the Token Bridge. -Mayan MCTP is a cross-chain intents protocol that leverages Circle's CCTP (Cross-Chain Transfer Protocol) mechanism and Wormhole messaging to enable secure, fee-managed asset transfers across chains. +- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** -![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp) + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains + - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards -### Protocol Flow: How It Works +- **Tokenized Gaming Rewards** -1. **Initiation** - the user creates an order by signing a transaction that locks one USDC into the Mayan smart contract, specifying the desired outcome. + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains - !!!note - If the input asset is not USDC, it is converted into a primary asset within the same transaction before the order is submitted. - - The contract constructs a `BridgeWithFeeMsg` structure, which includes parameters such as the action type, payload type, nonce, destination address, gas drop, redeem fee, and an optional custom payload hash +- **Multichain DeFi Arbitrage** -2. **Intent submission** - the contract calls the CCTP messenger to deposit the tokens for bridging. A unique nonce is generated, and a corresponding fee-lock record is created in the contract's storage. This record includes the locked fee, gas drop parameters, and destination details. The constructed message is hashed and published through Wormhole. The protocol fee is deducted during this step, and the Wormhole message is broadcast with the specified [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} -3. **Fulfillment** - on the destination chain, the protocol receives a CCTP message with corresponding signatures and verifies the payload using Wormhole's verification mechanism. Once validated, the redeemed tokens are transferred to the intended recipient, deducting the redeem fee as per protocol rules + - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets + - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms -The protocol provides mechanisms for unlocking the fee once the bridging process is completed. This can occur immediately upon fulfillment or be batched for efficiency. In the fee unlock flow, the contract verifies the unlock message via Wormhole and then releases the locked fee to the designated unlocker address. +## Next Steps -## Where to Go Next +If you are looking for more guided practice, take a look at: -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide -- To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/settlement/faqs/ +Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ --- BEGIN CONTENT --- --- -title: Wormhole Settlement FAQs -description: Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. -categories: Settlement, Transfer +title: Create Multichain Tokens +description: Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. --- -# Wormhole Settlement FAQs - -## Can I use Wormhole Settlement from a smart contract? If so, how is a message signed and relayed? - -Yes, Wormhole Settlement can be used from a smart contract. The composing protocol's relayer relays the message. For example, Mayan Shuttle (formerly Swap Layer) has a relayer that redeems the VAA on the destination chain to mint USDC and execute the `callData` contained in the payload. +# Create Multichain Tokens -## What happens if no solver participates in the auction? +## Introduction -If an auction does not start within the specified deadline, a standard CCTP transfer will proceed directly from the source chain to the destination chain. This is why parameters like `deadline` exist in the token router interface, ensuring a fallback mechanism in case no solver participates. +Blockchain ecosystems are becoming increasingly interconnected, with assets often needing to exist across multiple networks to maximize their utility and reach. For example, tokens created on one chain may want to expand to others to tap into broader audiences and liquidity pools. -## What guarantees does Wormhole Settlement provide for message execution? +This guide explains how to create a multichain token—a token that seamlessly bridges across blockchains using the Wormhole protocol. The process is designed to be user-friendly. With just a few steps, your token can become multichain, enabling it to be traded or used on various networks. -After the user receives the token upfront, the execution of additional contract calls depends on the relayer of the composing protocol. For example, in Mayan Shuttle, the relayer will attempt the swap multiple times, but its success is subject to the parameters defined in the `callData` (e.g., slippage). +By the end of this tutorial, you'll learn: -If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. ---- END CONTENT --- +- How to register your token for bridging +- How to create a wrapped version of your token +- How to ensure its visibility on blockchain explorers -Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +Let’s begin with a straightforward, step-by-step process for creating a multichain token and expanding its reach. -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- +## Register the Token on the Source Chain -# Build on the Wormhole Liquidity Layer +The first step in creating a multichain token is registering your token on its source chain. This ensures the token is prepared for bridging across blockchains. Follow these steps: -## Introduction +1. Open the [Portal Bridge](https://portalbridge.com/advanced-tools/#/register){target=\_blank} +2. Select the blockchain where your token is currently deployed (source chain) +3. Connect your wallet by following the on-screen instructions +4. Locate the **Asset** field and paste the token contract address +5. Click **Next** to proceed -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. +![Source Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp) -## EVM Functions +## Register the Token on the Target Chain -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. +After registering your token on the source chain, the next step is to select the target chain—the blockchain where you want the wrapped version of your token to exist. This step connects your token to its destination network. -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +1. Choose the blockchain where you want the token to be bridged (target chain) +2. Connect your wallet to the target chain +3. Click **Next** to finalize the registration process -### Fast Market Order +![Target Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp) -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` +## Send an Attestation +Attestation is a key step in the process. It verifies your token’s metadata, ensuring it is correctly recognized on the target chain’s blockchain explorer (e.g., [Etherscan](https://etherscan.io/){target=\_blank}). -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` +1. Click **Attest** to initiate the attestation process +2. Approve the transaction in your wallet when prompted -??? interface "Parameters `placeFastMarketOrder()`" +![Send Attestation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp) - `amountIn` ++"uint128"++ +!!! note + - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token + - Ensure you have sufficient funds to cover transaction fees on the target chain - The amount to transfer. +## Create the Wrapped Token - --- +The final step is to create the wrapped token on the target chain. This token represents the original asset and enables its use within the target blockchain. - `targetChain` ++"uint16"++ +1. Click **Create** to generate the wrapped token +2. Approve the transaction in your wallet when prompted - Target chain ID. +![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) - --- +Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: - `redeemer` ++"bytes32"++ +![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) - Redeemer contract address. +## Additional Steps and Recommendations - --- +After creating your multichain token, there are a few optional but highly recommended steps to ensure the best experience for users interacting with your token. - `redeemerMessage` ++"bytes"++ +### Add Your Token to the Wormhole Metadata List (Legacy) - An arbitrary payload for the redeemer. +For legacy compatibility in the [**Advanced Tools**](https://portalbridge.com/advanced-tools/){target=\_blank} section of Portal Bridge, you can request updates to your token metadata. Follow these steps: - --- +1. Join the [Wormhole Discord server](https://discord.com/invite/wormholecrypto){target=\_blank} +2. Submit a request for metadata updates in the appropriate support channel - `maxFee` ++"uint128"++ +!!! note + These updates only apply to the **Advanced Tools** section of Portal Bridge and will not update how your token appears in other Wormhole-powered apps or on blockchain explorers like Etherscan. - The maximum fee the user wants to pay to execute a fast transfer. +### Update Metadata on Blockchain Explorers - --- +It is recommended that you update your token’s metadata on blockchain explorers such as Etherscan. This includes adding details like the token logo, price, and contract verification. - `deadline` ++"uint32"++ +1. Create an account on the relevant scanner and go to the [token update section](https://etherscan.io/tokenupdate){target=\_blank} (or the relevant scanner that you would like to update metadata on) +2. Copy and paste the wrapped contract address in the **Token Update Application Form** +3. Before proceeding to the next step, you will need to verify as the contract address owner on [Etherscan’s address verification tool](https://etherscan.io/verifyAddress/){target=\_blank} +4. Follow the directions to verify contract address ownership via MetaMask by reviewing the [guide on verifying address ownership](https://info.etherscan.com/how-to-verify-address-ownership/){target=\_blank} + - Given that Wormhole may be the contract owner, use the manual verification process by reaching out through the [Etherscan contact form](https://etherscan.io/contactus){target=\_blank}. The team will provide support as needed +5. Once the step above is completed, follow the [instructions to update token information](https://info.etherscan.com/how-to-update-token-information-on-token-page/){target=\_blank} +--- END CONTENT --- - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. +Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/transfer-workflow/ +--- BEGIN CONTENT --- +--- +title: Transfer Tokens via Token Bridge Tutorial +description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains +--- -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. +# Complete Token Transfer Workflow -### Market Order +:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. +## Introduction -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` +This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. -??? interface "Parameters `placeMarketOrder()`" +By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: - `amountIn` ++"uint128"++ + - EVM to EVM (e.g., Ethereum to Avalanche) + - EVM to non-EVM chains (e.g., Ethereum to Solana) + - Non-EVM to EVM chains (e.g., Sui to Avalanche) + - Non-EVM to non-EVM chains (e.g., Solana to Sui) - The amount to transfer. +Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. - --- +At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. - `targetChain` ++"uint16"++ +## Prerequisites - Target chain ID. +Before you begin, ensure you have the following: - --- + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally + - Native tokens (testnet or mainnet) in Solana and Sui wallets + - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees - `redeemer` ++"bytes32"++ +## Supported Chains - Redeemer contract address. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. - --- +## Project Setup - `redeemerMessage` ++"bytes"++ +In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. - An arbitrary payload for the redeemer. +1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- + ```bash + mkdir native-transfers + cd native-transfers + npm init -y + ``` -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- +2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control -# Run a Wormhole Settlement Solver + ```bash + echo ".env" >> .gitignore + ``` -## Introduction +3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. + ```bash + npm install @wormhole-foundation/sdk dotenv tsx + ``` -A Solver is an off-chain agent responsible for: +4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana + ```bash + touch .env + ``` -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. + Inside the `.env` file, add your private keys. -## Background + ```env + ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" + SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" + ``` -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: + !!! note + Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners +5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays -These instructions work together to carry out the auction as follows: + 1. Create the helpers file -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent + ```bash + mkdir -p src/helpers + touch src/helpers/helpers.ts + ``` -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. + 2. Open the `helpers.ts` file and add the following code -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. + ```typescript + import { + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, + Chain, + TokenId, + isTokenId, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import { config } from 'dotenv'; +config(); -## Testnet Example Solver +export interface SignerStuff { + chain: ChainContext; + signer: Signer; + address: ChainAddress; +} -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. +// Function to fetch environment variables (like your private key) +function getEnv(key: string): string { + const val = process.env[key]; + if (!val) throw new Error(`Missing environment variable: ${key}`); + return val; +} -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. +// Signer setup function for different blockchain platforms +export async function getSigner( + chain: ChainContext, + gasLimit?: bigint +): Promise<{ + chain: ChainContext; + signer: Signer; + address: ChainAddress; +}> { + let signer: Signer; + const platform = chain.platform.utils()._platform; -### Prerequisites + switch (platform) { + case 'Solana': + signer = await ( + await solana() + ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); + break; + case 'Evm': + const evmSignerOptions = gasLimit ? { gasLimit } : {}; + signer = await ( + await evm() + ).getSigner( + await chain.getRpc(), + getEnv('ETH_PRIVATE_KEY'), + evmSignerOptions + ); + break; + case 'Sui': + signer = await ( + await sui() + ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); + break; + case 'Aptos': + signer = await ( + await aptos() + ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); + break; + default: + throw new Error('Unsupported platform: ' + platform); + } -In order to build and install dependencies locally in this repo, you will need: + return { + chain, + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} +export async function getTokenDecimals< + N extends 'Mainnet' | 'Testnet' | 'Devnet' +>( + wh: Wormhole, + token: TokenId, + sendChain: ChainContext +): Promise { + return isTokenId(token) + ? Number(await wh.getDecimals(token.chain, token.address)) + : sendChain.config.nativeTokenDecimals; +} + + ``` -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: + - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file + - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file + - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers -```sh -make dependencies -``` +## Check and Create Wrapped Tokens -### Set up Config +Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. +In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - } - ] -} -``` +### Configure the Wrapped Token Script -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. +1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory -### Listen to Activity + ```bash + mkdir -p src/scripts + touch src/scripts/create-wrapped.ts + ``` -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. +2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` + ```typescript + import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; + ``` -You should see output resembling: +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support -
    - Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
    + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: + !!! note + You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. -=== "Linux" +4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 + ```typescript + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); ``` -=== "MacOS" +5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 + ```typescript + ``` -### Running the Example Solver - -Using the same config for your publisher, run the example solver with the command below. +6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation -```sh -CONFIG=path/to/config.json make run-solver -``` + ```typescript + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } + ``` -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. + If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. -This process reads the following environment variables: +7. **Set up the source chain signer** - the signer creates and submits the attestation transaction -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` + ```typescript + + ``` -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. +8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. + ```typescript + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); + ``` -An address lookup table is required to execute some transactions. Use the command below to create one. +9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure -```sh -CONFIG=path/to/config.json make create-lut -``` + ```typescript + console.log('Parsed Messages:', msgs); -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } + ``` -The example solver has the following toggles depending on which orders you want to fulfill: +10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` + ```typescript + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. + const tsx = await signSendWait(destChain, subAttestation, destSigner); + ``` -This example solver does NOT do the following: +11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- + ```typescript + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } -Doc-Content: https://wormhole.com/docs/products/settlement/overview/ ---- BEGIN CONTENT --- ---- -title: Settlement Overview -description: Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. -categories: Settlement, Transfer ---- + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` -# Settlement Overview + If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. -Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. +??? code "Complete script" + ```typescript + import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { inspect } from 'util'; +import { getSigner } from '../helpers/helpers'; -Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); -It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. + // Define the source and destination chains + const srcChain = wh.getChain('ArbitrumSepolia'); + const destChain = wh.getChain('BaseSepolia'); + const token = await srcChain.getNativeWrappedTokenId(); + const gasLimit = BigInt(2_500_000); -## Key Features + // Destination chain signer setup + const { signer: destSigner } = await getSigner(destChain, gasLimit); + const tbDest = await destChain.getTokenBridge(); -- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. -- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. -- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. -- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. -- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. + try { + const wrapped = await tbDest.getWrappedAsset(token); + console.log( + `Token already wrapped on ${destChain.chain}. Skipping attestation.` + ); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.log( + `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` + ); + } -## How It Works + // Source chain signer setup + const { signer: origSigner } = await getSigner(srcChain); -At the core of Settlement are two components: + // Create an attestation transaction on the source chain + const tbOrig = await srcChain.getTokenBridge(); + const attestTxns = tbOrig.createAttestation( + token.address, + Wormhole.parseAddress(origSigner.chain(), origSigner.address()) + ); -- **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. -- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. + const txids = await signSendWait(srcChain, attestTxns, origSigner); + console.log('txids: ', inspect(txids, { depth: null })); + const txid = txids[0]!.txid; + console.log('Created attestation (save this): ', txid); -Settlement leverages the following three integrated protocols. - -### Mayan Swift + // Retrieve the Wormhole message ID from the attestation transaction + const msgs = await srcChain.parseTransaction(txid); + console.log('Parsed Messages:', msgs); -Mayan Swift implements a traditional intent-based architecture, where solvers compete to fulfill user intents by utilizing their inventory. It offers fast execution, typically around 12 seconds. To participate, solvers must hold assets on multiple chains, which can lead to imbalances: some chains may get depleted while others accumulate excess. This requires occasional rebalancing and adds operational overhead. Despite that, Mayan Swift is ideal for high-speed transfers and benefits from open, competitive auctions that can drive down execution prices. + const timeout = 25 * 60 * 1000; + const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); + if (!vaa) { + throw new Error( + 'VAA not found after retries exhausted. Try extending the timeout.' + ); + } -The diagram below shows how Mayan Swift handles a cross-chain intent when a user wants to swap ARB on Arbitrum for WIF on Solana. Behind the scenes, the process is more involved and relies on solver-managed liquidity across both chains. + console.log('Token Address: ', vaa.payload.token.address); -1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. -2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. -3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. -4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. + // Submit the attestation on the destination chain + console.log('Attesting asset on destination chain...'); -```mermaid -sequenceDiagram - participant User - participant Solver_ARB as Solver (Arbitrum) - participant Escrow - participant Wormhole - participant Solver_SOL as Solver (Solana) - participant Aggregator + const subAttestation = tbDest.submitAttestation( + vaa, + Wormhole.parseAddress(destSigner.chain(), destSigner.address()) + ); - Note over User,Aggregator: User has ARB and wants WIF + const tsx = await signSendWait(destChain, subAttestation, destSigner); + console.log('Transaction hash: ', tsx); - User->>Solver_ARB: Submit intent (ARB → WIF) - Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH - Escrow-->>Wormhole: Emits VAA - Wormhole-->>Solver_SOL: Delivers VAA - Solver_SOL->>Aggregator: Releases SOL and swaps to WIF - Aggregator->>Solver_SOL: Receives WIF - Solver_SOL->>User: Sends WIF - User-->>Wormhole: Emits final VAA - Wormhole-->>Escrow: Confirms receipt - Escrow->>Solver_ARB: Releases ETH to solver -``` + // Poll for the wrapped asset until it's available + async function waitForIt() { + do { + try { + const wrapped = await tbDest.getWrappedAsset(token); + return { chain: destChain.chain, address: wrapped }; + } catch (e) { + console.error('Wrapped asset not found yet. Retrying...'); + } + console.log('Waiting before checking again...'); + await new Promise((r) => setTimeout(r, 2000)); + } while (true); + } -### Liquidity Layer + console.log('Wrapped Asset: ', await waitForIt()); +})().catch((e) => console.error(e)); + ``` -The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. +### Run the Wrapped Token Creation -### Mayan MCTP +Once the script is ready, execute it with: -Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. +```bash +npx tsx src/scripts/create-wrapped.ts +``` -### One Integration, Three Ways +If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. -Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. +## Token Transfers -By default, Settlement integrates all three: +In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. -- The SDK automatically resolves the best route for each transfer. -- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. -- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. +### Configure Transfer Details -Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. +Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. -To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. +1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains -## Use Cases + ```bash + touch src/scripts/native-transfer.ts + ``` -- **Cross-Chain Perpetuals** +2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + ```typescript + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; + ``` -- **Bridging Intent Library** +3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + ```typescript + const wh = await wormhole('Testnet', [evm, solana, sui]); + ``` -- **Multichain Prediction Markets** +4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + ```typescript + const rcvChain = wh.getChain('Solana'); + ``` -## Next Steps +5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains -Start building with Settlement or dive deeper into specific components: + ```typescript + const destination = await getSigner(rcvChain); + ``` -- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. -- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. -- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. ---- END CONTENT --- +6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object -Doc-Content: https://wormhole.com/docs/products/settlement/tutorials/.settlement-routes/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlements -description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. ---- + ```typescript + + ``` -# Integrate Wormhole Settlement Routes Using the SDK +7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit -## Introduction + ```typescript + + ``` -This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. +8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself -## Prerequisites + ```typescript + + ``` -Before beginning this project, make sure you have the following: + !!! note + Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. + +9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function -- **Wormhole SDK Route package** - installed using your preferred package manager + ```typescript + + ``` - To install the package with npm, run the following command in your terminal: +10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` - ```sh - npm install @mayan-finance/wormhole-sdk-route + ```typescript + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); ``` - Alternatively, clone the repository and install dependencies: + Finally, we use `process.exit(0);` to close the script once the transfer completes - ```sh - git clone https://github.com/mayan-finance/wormhole-sdk-route.git - cd wormhole-sdk-route - npm install + ```typescript + })(); ``` -- **Data for parameters** - you will need: - - - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - - An contract address for the token you want to swap and the token you want to receive on the destination chain +### Token Transfer Logic -## Configure and Setup +This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. -To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: +#### Defining the Token Transfer Function -- `sourceChain` - identifier for the chain where the swap begins -- `destinationChain` - identifier for the target chain -- `inputTokenAddress` - address of the token you want to swap -- `outputTokenAddress` - identifier/address of the desired token on the destination chain -- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) -- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) +The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; +```typescript +wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic +import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; -const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana - amount: '1000000000000000000', // For instance, 1 token in wei - slippageTolerance: 0.005, // 0.5% slippage tolerance - // Additional parameters may be included as needed -}; +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); -const swapRoute = new SwapRoute(config); -``` + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); -## Execute a Swap + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); -Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); -### Fetch the Swap Route + // Define the amount of tokens to transfer + const amt = '1'; -Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: + // Set automatic transfer to false for manual transfer + const automatic = false; -```ts -async function getSwapDetails() { - try { - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - return routeDetails; - } catch (error) { - console.error('Error fetching swap route:', error); - throw error; - } -} - -getSwapDetails(); -``` + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); -### Execute the Swap Transaction + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); -Once the route is confirmed, execute the swap: + process.exit(0); +})(); -```ts -async function executeSwap() { - try { - const txResponse = await swapRoute.executeSwap(); - console.log('Swap executed successfully:', txResponse); - // Further transaction handling (e.g., waiting for confirmation) can be added here. - } catch (error) { - console.error('Swap execution failed:', error); +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; } -} - -executeSwap(); -``` - -## Complete Example Integration - -Below is a complete example that puts together configuration, route fetching, and swap execution: +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); -async function performSwap() { - // Configure the swap parameters - const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', - amount: '1000000000000000000', - slippageTolerance: 0.005, - // Include additional settings as needed - }; + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; - // Initialize the swap route - const swapRoute = new SwapRoute(config); + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); - try { - // Retrieve the optimal swap route details - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); - // Execute the swap transaction - const txResponse = await swapRoute.executeSwap(); - console.log('Swap Transaction Response:', txResponse); - } catch (error) { - console.error('An error occurred during the swap process:', error); - } + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); } - -performSwap(); + ``` -## Error Handling and Troubleshooting - -- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable -- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting -- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: - - ```ts - class MayanRefRoute extends MayanRoute { - override referrerAddress(): ReferrerAddresses | undefined { - return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; - } - } - ``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ ---- BEGIN CONTENT --- ---- -title: Token Bridge Payload Structure -description: Discover the structure and purpose of each Token Bridge payload, including Transfer, TransferWithPayload, AssetMeta, and governance messages. -categories: Token-Bridge, Transfers ---- - -# Message and Payload Structure +#### Steps to Transfer Tokens -To enable secure and flexible cross-chain token transfers, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} defines a set of standardized payloads. These payloads are embedded in [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} and processed by bridge contracts on the source and destination chains. Each payload has a unique format and serves a specific role in the lifecycle of token bridging. +The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: -This page outlines each payload type in detail. +1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step -## Transfer + ```typescript + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); + ``` -The `Transfer` payload (ID = `1`) is the core mechanism for moving tokens across chains. It is emitted when a user locks or burns tokens on the source chain. On the destination chain, it instructs the bridge to either mint a wrapped token or release native tokens from custody. +2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying -```text -PayloadID uint8 = 1 -Amount uint256 -TokenAddress bytes32 -TokenChain uint16 -To bytes32 -ToChain uint16 -Fee uint256 -``` + ```typescript + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); -??? interface "Parameters" + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; + ``` - `PayloadID` ++"uint8"++ +3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process - Value must be `1`, indicating a `Transfer` operation. + ```typescript + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + ``` - --- + - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} - `Amount` ++"uint256"++ + ???- note "How Cross-Chain Transfers Work in the Background" + When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: - Amount being transferred, truncated to 8 decimals for consistency across all chains. + - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount + - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains + - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network + - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer - --- + This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. - `TokenAddress` ++"bytes32"++ +4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain - Address of the token. Left-zero-padded if shorter than 32 bytes + ```typescript - --- + ``` - `TokenChain` ++"uint16"++ +5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer - Chain ID of the token. - - --- + ```typescript + console.log(`Completed Transfer: `, destTxids); + ``` - `To` ++"bytes32"++ +??? code "Complete script" + ```typescript + import { + Chain, + Network, + Wormhole, + amount, + wormhole, + TokenId, + TokenTransfer, +} from '@wormhole-foundation/sdk'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - Address of the recipient. Left-zero-padded if shorter than 32 bytes. - - --- +(async function () { + const wh = await wormhole('Testnet', [evm, solana, sui]); - `ToChain` ++"uint16"++ + // Set up source and destination chains + const sendChain = wh.getChain('Sui'); + const rcvChain = wh.getChain('Solana'); - Chain ID of the recipient. - - --- + // Get signer from local key but anything that implements + const source = await getSigner(sendChain); + const destination = await getSigner(rcvChain); - `Fee` ++"uint256"++ + // Shortcut to allow transferring native gas token + const token = Wormhole.tokenId(sendChain.chain, 'native'); - Amount of tokens that the user is willing to pay as relayer fee. Must be less than Amount. Optional and can be claimed by relayers who submit the VAA on the target chain. - + // Define the amount of tokens to transfer + const amt = '1'; -To keep `Transfer` messages small, they don't carry all the token's metadata. However, this means that before a token can be transferred to a new chain for the first time, the metadata needs to be bridged, and the wrapped asset needs to be created. Metadata, in this case, includes the number of decimals, which is a core requirement for instantiating a token. + // Set automatic transfer to false for manual transfer + const automatic = false; -## AssetMeta + // Used to normalize the amount to account for the tokens decimals + const decimals = await getTokenDecimals(wh, token, sendChain); -Before a token can be transferred to a new chain for the first time, its metadata must be attested using the `AssetMeta` payload (ID = `2`). This ensures proper decimal precision and display. + // Perform the token transfer if no recovery transaction ID is provided + const xfer = await tokenTransfer(wh, { + token, + amount: amount.units(amount.parse(amt, decimals)), + source, + destination, + automatic, + }); -```text -PayloadID uint8 = 2 -TokenAddress [32]uint8 -TokenChain uint16 -Decimals uint8 -Symbol [32]uint8 -Name [32]uint8 -``` - -??? interface "Parameters" - - `PayloadID` ++"uint8"++ - - Value must be `2`, indicating a `AssetMeta` operation. - - --- + process.exit(0); +})(); - `TokenAddress` ++"[32]uint8"++ +async function tokenTransfer( + wh: Wormhole, + route: { + token: TokenId; + amount: bigint; + source: SignerStuff; + destination: SignerStuff; + automatic: boolean; + payload?: Uint8Array; + } +) { + // Token Transfer Logic + // Create a TokenTransfer object to track the state of the transfer over time + const xfer = await wh.tokenTransfer( + route.token, + route.amount, + route.source.address, + route.destination.address, + route.automatic ?? false, + route.payload + ); - Address of the token. Left-zero-padded if shorter than 32 bytes. + const quote = await TokenTransfer.quoteTransfer( + wh, + route.source.chain, + route.destination.chain, + xfer.transfer + ); - --- + if (xfer.transfer.automatic && quote.destinationToken.amount < 0) + throw 'The amount requested is too low to cover the fee and any native gas requested.'; - `TokenChain` ++"uint16"++ + // Submit the transactions to the source chain, passing a signer to sign any txns + console.log('Starting transfer'); + const srcTxids = await xfer.initiateTransfer(route.source.signer); + console.log(`Source Trasaction ID: ${srcTxids[0]}`); + console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); - Chain ID of the token. + // Wait for the VAA to be signed and ready (not required for auto transfer) + console.log('Getting Attestation'); + await xfer.fetchAttestation(60_000); - --- + // Redeem the VAA on the dest chain + console.log('Completing Transfer'); + const destTxids = await xfer.completeTransfer(route.destination.signer); + console.log(`Completed Transfer: `, destTxids); +} + + ``` - `Decimals` ++"uint8"++ +### Run the Native Token Transfer - Number of decimals the token uses on its native chain (not truncated to 8). +Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: - --- +```bash +npx tsx src/scripts/native-transfer.ts +``` - `Symbol` ++"[32]uint8"++ +This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). - Symbol of the token, UTF-8 encoded and padded to 32 bytes. +You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. - --- +## Resources - `Name` ++"[32]uint8"++ +If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. - Name of the token, UTF-8 encoded and padded to 32 bytes. +## Conclusion -## TransferWithPayload +You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. -The `TransferWithPayload` payload (ID = `3`) extends the standard token transfer by allowing developers to include arbitrary data. This enables interactions with destination chain smart contracts, such as triggering swaps or staking. +The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. +--- END CONTENT --- -```text -PayloadID uint8 = 3 -Amount uint256 -TokenAddress bytes32 -TokenChain uint16 -To bytes32 -ToChain uint16 -FromAddress bytes32 -Payload bytes -``` +Doc-Content: https://wormhole.com/docs/protocol/architecture/ +--- BEGIN CONTENT --- +--- +title: Architecture +description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +categories: Basics +--- -??? interface "Parameters" +# Architecture - `PayloadID` ++"uint8"++ +## Overview - Value must be `3`, indicating a `TransferWithPayload` operation. +Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. - --- +![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) - `Amount` ++"uint256"++ +The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: - Amount being transferred, truncated to 8 decimals. +1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs +2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} +3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain +4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. - --- + The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: - `TokenAddress` ++"bytes32"++ + - In some applications, the target contract acts as the entry point and performs verification via the Core Contract + - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract - Address of the token. Left-zero-padded if shorter than 32 bytes. +## On-Chain Components - --- +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication +- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract - `TokenChain` ++"uint16"++ +## Off-Chain Components - Chain ID of the token. +- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) +- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig +- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution +- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network +- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract +- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain + - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract + - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers - --- +## Next Steps - `To` ++"bytes32"++ +
    - Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes +- :octicons-book-16:{ .lg .middle } **Core Contracts** --- - `ToChain` ++"uint16"++ - - Chain ID of the recipient. - - --- + Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. - `FromAddress` ++"bytes32"++ + [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) - Address of the sender on the source chain. +- :octicons-tools-16:{ .lg .middle } **Core Messaging** --- - `Payload` ++"bytes"++ - - Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic. - - -Unlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly. + Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. -## RegisterChain + [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) -The `RegisterChain` governance payload (Action ID = `1`) registers a Token Bridge emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers. +
    +--- END CONTENT --- -```text -Module [32]byte -Action uint8 = 1 -ChainId uint16 +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ +--- BEGIN CONTENT --- +--- +title: Run a Relayer +description: Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. +categories: Relayers +--- -EmitterChainID uint16 -EmitterAddress [32]uint8 -``` +# Run a Custom Relayer -??? interface "Parameters" +## Introduction - `Module` ++"[32]byte"++ +Relayers play a crucial role in cross-chain communication, ensuring that messages are transferred seamlessly between different blockchains. While Wormhole relayers provide a reliable way to handle these transfers, they might not always meet every application's unique requirements. - Module identifier. Left-padded with `TokenBridge` for Token Bridge. +Custom relayers address these limitations by offering tailored solutions that cater to the distinct needs of your application. Developing a custom relayer gives you complete control over message processing, delivery mechanisms, and integration with existing systems. This customization allows for optimized performance and the ability to implement specific features that Wormhole-deployed relayers might not support. - --- +A custom relayer might be as simple as an in-browser process that polls the API for the availability of a VAA after submitting a transaction and delivers it to the target chain. It might also be implemented with a Spy coupled with some daemon listening for VAAs from a relevant chain ID and emitter, then taking action when one is observed. - `Action` ++"uint8"++ +This guide teaches you how to set up and configure a custom relayer for efficient message handling. You'll start by understanding how to uniquely identify a VAA using its emitter address, sequence ID, and chain ID. Then, you'll explore the Relayer Engine, a package that provides a framework for building custom relayers, and learn how to fetch and handle VAAs using the Wormhole SDK. - Value must be `1`, indicating a `RegisterChain` operation. +## Get Started with a Custom Relayer - --- +To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs. - `ChainID` ++"uint16"++ +
    + ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp) +
    The off-chain components outlined in blue must be implemented.
    +
    - The chain where this governance action should be applied. `0` is a valid value for all chains +### How to Uniquely Identify a VAA - --- +Regardless of the environment, to get the VAA you intend to relay, you need: - `EmitterChainID` ++"uint16"++ +- The `emitter` address +- The `sequence` ID of the message you're interested in +- The `chainId` for the chain that emitted the message - Chain ID of the registered emitter. +With these three components, you're able to uniquely identify a VAA and process it. - --- +## Use the Relayer Engine - `EmitterAddress` ++"[32]uint8"++ +The [`relayer-engine`](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} is a package that provides the structure and a starting point for a custom relayer. - Address of the registered emitter, left-zero-padded if shorter than 32 bytes. +With the Relayer Engine, a developer can write specific logic for filtering to receive only the messages they care about. -This payload can only be emitted by the Wormhole governance contract, ensuring that each chain accepts messages only from one verified bridge emitter per remote chain. +Once a Wormhole message is received, the developer may apply additional logic to parse custom payloads or submit the Verifiable Action Approvals (VAA) to one or many destination chains. -## UpgradeContract +To use the Relayer Engine, a developer may specify how to relay Wormhole messages for their app using an idiomatic Express/Koa middleware-inspired API, then let the library handle all the details. -The `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the Token Bridge contract on a specific chain. +### Install the Relayer Engine -```text -Module [32]byte -Action uint8 = 2 -ChainId uint16 +First, install the `relayer-engine` package with your favorite package manager: -NewContract [32]uint8 +```bash +npm i @wormhole-foundation/relayer-engine ``` -??? interface "Parameters" - - `Module` ++"[32]byte"++ +### Get Started with the Relayer Engine - Module identifier, left-padded with `TokenBridge` for Token Bridge. +In the following example, you'll: - --- +1. Set up a `StandardRelayerApp`, passing configuration options for our relayer +2. Add a filter to capture only those messages our app cares about, with a callback to do _something_ with the VAA once received +3. Start the relayer app - `Action` ++"uint8"++ +```typescript +import { + Environment, + StandardRelayerApp, + StandardRelayerContext, +} from '@wormhole-foundation/relayer-engine'; +import { CHAIN_ID_SOLANA } from '@certusone/wormhole-sdk'; - Value must be `2`, indicating an `UpgradeContract` operation. - - --- +(async function main() { + // Initialize relayer engine app and pass relevant config options + const app = new StandardRelayerApp( + Environment.TESTNET, + // Other app specific config options can be set here for things + // like retries, logger, or redis connection settings + { + name: 'ExampleRelayer', + } + ); - `ChainID` ++"uint16"++ + // Add a filter with a callback that will be invoked + // on finding a VAA that matches the filter + app.chain(CHAIN_ID_SOLANA).address( + // Emitter address on Solana + 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', + // Callback function to invoke on new message + async (ctx, next) => { + const vaa = ctx.vaa; + const hash = ctx.sourceTxHash; + console.log( + `Got a VAA with sequence: ${vaa.sequence} from with txhash: ${hash}` + ); + } + ); - The target chain where the governance action should be applied. + // Add and configure any other middleware here - --- + // Start app. Blocks until unrecoverable error or process is stopped + await app.listen(); +})(); + +``` - `NewContract` ++"[32]uint8"++ +The first meaningful line instantiates the `StandardRelayerApp`, a subclass of the `RelayerApp` with standard defaults. - Address of the new Token Bridge contract, left-zero-padded to 32 bytes. +```typescript +export class StandardRelayerApp< + ContextT extends StandardRelayerContext = StandardRelayerContext, +> extends RelayerApp { + // ... + constructor(env: Environment, opts: StandardRelayerAppOpts) { +``` -This message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security. +The only field you pass in the `StandardRelayerAppOpts` is the name to help identify log messages and reserve a namespace in Redis. -## Summary of Payload Structure +??? code "`StandardRelayerAppOpts`" -| Payload Type | ID | Purpose | Who Emits It | -|-----------------------|---------------|------------------------------------------------------------------------|------------------------| -| `Transfer` | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination | Token Bridge contract | -| `AssetMeta` | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer | Token Bridge contract | -| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution | Token Bridge contract | -| `RegisterChain` | Action `1` | Registers a verified Token Bridge emitter for a foreign chain | Wormhole governance | -| `UpgradeContract` | Action `2` | Upgrades the Token Bridge contract on a specific chain | Wormhole governance | ---- END CONTENT --- + Other options can be passed to the `StandardRelayerApp` constructor to configure the app further. -Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ ---- BEGIN CONTENT --- ---- -title: Flow of a Token Bridge Transfer -description: Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. -categories: Token-Bridge, Transfer ---- + ```typescript + wormholeRpcs?: string[]; // List of URLs from which to query missed VAAs +concurrency?: number; // How many concurrent requests to make for workflows +spyEndpoint?: string; // The hostname and port of our Spy +logger?: Logger; // A custom Logger +privateKeys?: Partial<{ [k in ChainId]: any[]; }>; // A set of keys that can be used to sign and send transactions +tokensByChain?: TokensByChain; // The token list we care about +workflows?: { retries: number; }; // How many times to retry a given workflow +providers?: ProvidersOpts; // Configuration for the default providers +fetchSourceTxhash?: boolean; // whether or not to get the original transaction ID/hash +// Redis config +redisClusterEndpoints?: ClusterNode[]; +redisCluster?: ClusterOptions; +redis?: RedisOptions; + ``` -# Flow of a Transfer +The next meaningful line in the example adds a filter middleware component. This middleware will cause the relayer app to request a subscription from the Spy for any VAAs that match the criteria and invoke the callback with the VAA. -## Introduction +If you'd like your program to subscribe to `multiple` chains and addresses, you can call the same method several times or use the `multiple` helper. -The [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} enables token transfers across blockchains by combining token-specific logic with [Wormhole's core messaging layer](/docs/protocol/architecture/){target=\_blank}. Each supported chain runs its own Token Bridge contract, which manages actions like locking, burning, minting, and releasing tokens. These contracts communicate directly with Wormhole's core message-passing layer to securely transmit messages between chains. +```typescript +app.multiple( + { + [CHAIN_ID_SOLANA]: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', + [CHAIN_ID_ETH]: ['0xabc1230000000...', '0xdef456000...'], + }, + myCallback +); +``` -This guide provides a conceptual overview of the Token Bridge and its integration with the messaging layer. It outlines each step of the transfer flow and explains how different transfer types work in practice. +The last line in the simple example runs `await app.listen()`, which starts the relayer engine. Once started, the Relayer Engine issues subscription requests to the Spy and begins any other workflows (e.g., tracking missed VAAs). -## Transfer Flow +This will run until the process is killed or encounters an unrecoverable error. To gracefully shut down the relayer, call `app.stop()`. -Cross-chain token transfers using the Token Bridge follow these steps: +The source code for this example is available in the [`relayer-engine` repository](https://github.com/wormhole-foundation/relayer-engine/blob/main/examples/simple/src/app.ts){target=\_blank}. -1. **Initiation on the Source Chain** - The transfer begins when a user calls the Token Bridge contract on the source chain: +## Start Background Processes - - **Wrapped tokens**: The token is burned. - - **Original tokens**: If the token is native to the source chain, the token is locked in the contract. +!!! note + These processes _must_ be running for the relayer app below to work. -2. **Transfer Message Publication** - The Token Bridge contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}, which emits an on-chain message event describing the transfer. +Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. -3. **Message Observation and Signing** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank}—a decentralized network of validators—monitor the source chain for these message events. A supermajority (13 out of 19) signs the event to generate a [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}—a cryptographically signed attestation of the transfer. +More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. - The VAA is then published to the Wormhole network. +### Wormhole Network Spy -4. **VAA Submission to the Destination Chain** - The VAA must be submitted to the Token Bridge contract on the destination chain to complete the transfer. The Token Bridge contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways: +For our relayer app to receive messages, a local Spy must be running that watches the Guardian network. Our relayer app will receive updates from this Spy. - - **Automatic**: A relayer service detects the VAA and submits it to the Token Bridge contract. - - **Manual**: The user or dApp retrieves the VAA and submits it directly to the Token Bridge contract. +=== "Mainnet Spy" -5. **Finalization of the Transfer on the Destination Chain** - After the VAA is verified on the destination chain, the Token Bridge contract completes the transfer: + ```bash + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env mainnet + ``` - - **Wrapped tokens**: A wrapped representation of the original token is minted. - - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient. +=== "Testnet Spy" -Consider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s Token Bridge, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow. + ```bash + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env testnet + ``` -```mermaid -sequenceDiagram - participant Alice as Alice - participant TokenBridgeEth as Token Bridge Ethereum
    (Source Chain) - participant CoreEth as Core Contract Ethereum
    (Source Chain) - participant Guardians - participant TokenBridgeSol as Token Bridge Solana
    (Destination Chain) - participant CoreSol as Core Contract Solana
    (Destination Chain) +### Redis Persistence - Alice->>TokenBridgeEth: Initiate ETH transfer
    (lock ETH) - TokenBridgeEth->>CoreEth: Publish transfer message - CoreEth-->>Guardians: Emit message event - Guardians->>Guardians: Sign and publish VAA +!!! note + While you're using [Redis](https://redis.io/docs/latest/develop/get-started/){target=\_blank} here, the persistence layer can be swapped out for some other database by implementing the appropriate [interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank}. - alt Automatic VAA submission - Guardians->>TokenBridgeSol: Relayer submits VAA - else Manual VAA submission - Alice->>Guardians: Retrieve VAA - Alice->>TokenBridgeSol: Submit VAA - end +A Redis instance must also be available to persist job data for fetching VAAs from the Spy. - TokenBridgeSol->>CoreSol: Verify VAA - CoreSol-->>TokenBridgeSol: VAA verified - TokenBridgeSol-->>Alice: Mint wrapped ETH on Solana (complete transfer) +```bash +docker run --rm -p 6379:6379 --name redis-docker -d redis ``` -Maybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s Token Bridge, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow. - -```mermaid -sequenceDiagram - participant User as Alice - participant TokenBridgeSrc as Token Bridge Solana
    (Source Chain) - participant CoreSrc as Core Contract Solana
    (Source Chain) - participant Guardians - participant TokenBridgeDst as Token Bridge Ethereum
    (Destination Chain) - participant CoreDst as Core Contract Ethereum
    (Destination Chain) +## Use the Wormhole SDK - User->>TokenBridgeSrc: Initiate transfer
    (burn wrapped ETH) - TokenBridgeSrc->>CoreSrc: Publish message - CoreSrc-->>Guardians: Emit message event - Guardians->>Guardians: Sign and publish VAA +!!! note + The example below uses the legacy [`@certusone/wormhole-sdk`](https://www.npmjs.com/package/@certusone/wormhole-sdk){target=\_blank}, which is still supported and used in the Relayer Engine but is no longer actively maintained. + + For most use cases, it is recommend to use the latest [`@wormhole-foundation/sdk`](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}. - alt Automatic VAA submission - Guardians->>TokenBridgeDst: Relayer submits VAA - else Manual VAA submission - User->>Guardians: Retrieve VAA - User->>TokenBridgeDst: User submits VAA directly - end +You can also use the Wormhole SDK to poll the Guardian RPC until a signed VAA is ready using the SDK's `getSignedVAAWithRetry` function. - TokenBridgeDst->>CoreDst: Verify VAA - CoreDst-->>TokenBridgeDst: VAA verified - TokenBridgeDst-->>User: Release native ETH on Ethereum (Complete transfer) -``` +```ts +import { + getSignedVAAWithRetry, + parseVAA, + CHAIN_ID_SOLANA, + CHAIN_ID_ETH, +} from '@certusone/wormhole-sdk'; +const RPC_HOSTS = [ + /* ...*/ +]; -## Automatic vs. Manual Transfers +async function getVAA( + emitter: string, + sequence: string, + chainId: number +): Promise { + // Wait for the VAA to be ready and fetch it from the guardian network + const { vaaBytes } = await getSignedVAAWithRetry( + RPC_HOSTS, + chainId, + emitter, + sequence + ); + return vaaBytes; +} -The Token Bridge supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually: +const vaaBytes = await getVAA('INSERT_EMITTER_ADDRESS', 1, CHAIN_ID_ETH); + +``` -- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain. -- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain. +Once you have the VAA, the delivery method is chain-dependent. -Here's a quick breakdown of the key differences: +=== "EVM" -| Feature | Automatic Transfer | Manual Transfer | -|---------------------------|-----------------------------|-------------------------------------| -| Who submits the VAA? | Relayer | User or dApp | -| User Experience | Seamless, one-step | Requires manual intervention | -| Best for | End-users, simple UIs | Custom dApps, advanced control | -| Dependency | Requires relayer support | None | + On EVM chains, the bytes for the VAA can be passed directly as an argument to an ABI method. -### Completing Manual Transfers + ```ts + // Set up eth wallet +const ethProvider = new ethers.providers.StaticJsonRpcProvider( + 'INSERT_RPC_URL' +); +const ethWallet = new ethers.Wallet('INSERT_PRIVATE_KEY', ethProvider); -The user who initiated the transfer should complete the transfer within 24 hours for manual transfers. Guardian Sets are guaranteed to be valid for at least that long. If a user waits longer, the Guardian Set may have changed between initiation and redemption, causing the VAA to be rejected. +// Create client to interact with our target app +const ethHelloWorld = HelloWorld__factory.connect( + 'INSERT_CONTRACT_ADDRESS', + ethWallet +); -If this occurs, follow the [Replace Outdated Signatures in VAAs](){target=_blank} tutorial to update the VAA with signatures from the current Guardian Set. - -## Token Bridge Relayer (TBR) - -When completing an automatic transfer using the Token Bridge—either through [Connect](/docs/products/connect/overview/){target=\_blank} or programmatically via the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}—the Token Bridge Relayer (TBR) manages the interaction with the underlying Token Bridge contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\_blank}. - - +// Invoke the receiveMessage on the ETH contract and wait for confirmation +const receipt = await ethHelloWorld + .receiveMessage(vaaBytes) + .then((tx: ethers.ContractTransaction) => tx.wait()) + .catch((msg: any) => { + console.error(msg); + return null; + }); + ``` -### Flow of an Automatic Transfer via TBR +=== "Solana" -The flow of an automatic transfer using the TBR looks like this: + On Solana, the VAA is first posted to the core bridge, and then a custom transaction is prepared to process and validate the VAA. -1. **Initiation on the Source Chain** - The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called. + ```ts + import { CONTRACTS } from '@certusone/wormhole-sdk'; -2. **Prepare and Forward the Transfer** - The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to the Token Bridge. +export const WORMHOLE_CONTRACTS = CONTRACTS[NETWORK]; +export const CORE_BRIDGE_PID = new PublicKey(WORMHOLE_CONTRACTS.solana.core); -3. **Core Messaging Layer Processes the Transfer** - The Token Bridge emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. +// First, post the VAA to the core bridge +await postVaaSolana( + connection, + wallet.signTransaction, + CORE_BRIDGE_PID, + wallet.key(), + vaaBytes +); -4. **Off-Chain Relayer Observes the VAA** +const program = createHelloWorldProgramInterface(connection, programId); +const parsed = isBytes(wormholeMessage) + ? parseVaa(wormholeMessage) + : wormholeMessage; - An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer. +const ix = program.methods + .receiveMessage([...parsed.hash]) + .accounts({ + payer: new PublicKey(payer), + config: deriveConfigKey(programId), + wormholeProgram: new PublicKey(wormholeProgramId), + posted: derivePostedVaaKey(wormholeProgramId, parsed.hash), + foreignEmitter: deriveForeignEmitterKey(programId, parsed.emitterChain), + received: deriveReceivedKey( + programId, + parsed.emitterChain, + parsed.sequence + ), + }) + .instruction(); -5. **Relayer Computes Native Drop-Off and Submits the VAA** +const transaction = new Transaction().add(ix); +const { blockhash } = await connection.getLatestBlockhash(commitment); +transaction.recentBlockhash = blockhash; +transaction.feePayer = new PublicKey(payerAddress); - The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA. +const signed = await wallet.signTxn(transaction); +const txid = await connection.sendRawTransaction(signed); -6. **TBR Validates and Completes the Transfer** - - The destination TBR validates the VAA by invoking the Token Bridge contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens. +await connection.confirmTransaction(txid); + ``` +--- END CONTENT --- -6. **Asset Distribution on the Destination Chain** +Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-spy/ +--- BEGIN CONTENT --- +--- +title: Run a Spy +description: Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. +--- - The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens. +# Run a Spy -The following diagram illustrates the key steps on the source chain during a transfer: +## Introduction -```mermaid -sequenceDiagram - participant User - participant SourceTBR as Source Chain TBR - participant SourceTB as Source Chain Token Bridge - participant Messaging as Core Messaging Layer +The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. - User->>SourceTBR: Initiate transfer (token,
    recipient, fees, native gas) - SourceTBR->>SourceTB: Forward transfer (burn or lock tokens) - SourceTB->>Messaging: Publish transfer message -``` +For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. -Once the core messaging layer processes the transfer, the destination chain handles completion as shown below: +## How to Start a Spy -```mermaid -sequenceDiagram - participant Messaging as Core Messaging Layer - participant Relayer as Off-chain Relayer - participant DestTBR as Destination Chain TBR - participant DestTB as Destination Chain
    Token Bridge - participant DestUser as User
    (Destination Chain) +To start a Spy locally, run the following Docker command: - Messaging->>Relayer: Emit signed VAA for transfer - Relayer->>Relayer: Verifies destination chain and token registration - Relayer->>DestTBR: Query native gas amount - Relayer->>DestTBR: Submit signed VAA - DestTBR->>DestTB: Validate VAA - DestTBR->>DestTBR: Take custody of tokens - DestTBR->>DestUser: Send tokens (after fees & native gas) - DestTBR->>Relayer: Pay relayer fee & refund excess -``` +=== "Mainnet" -## Next Steps + ```sh + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env mainnet + ``` -Now that you’ve seen how a transfer works try both types yourself to experience the full process: +=== "Testnet" -- [Get Started with Token Bridge](/docs/products/token-bridge/get-started/){target=\_blank} ---- END CONTENT --- + ```sh + docker run --pull=always --platform=linux/amd64 \ + -p 7073:7073 \ + --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ + spy \ + --nodeKey /node.key \ + --spyRPC "[::]:7073" \ + --env testnet + ``` -Doc-Content: https://wormhole.com/docs/products/token-bridge/faqs/ ---- BEGIN CONTENT --- ---- -title: Token Bridge FAQs -description: Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. -categories: Token-Bridge, Transfer ---- +If you want to run the Spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image. -# FAQs +Optionally, add the following flags to skip any VAAs with invalid signatures: -## Can ownership of wrapped tokens be transferred from the Token Bridge? +=== "Mainnet" -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. + ```sh + --ethRPC https://eth.drpc.org + --ethContract 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B + ``` - - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge +=== "Testnet" -The logic behind deploying these token contracts involves submitting an attestation VAA, which allows the Token Bridge to verify and deploy the wrapped token contract on the destination chain. + ```sh + --ethRPC https://sepolia.drpc.org/ + --ethContract 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 + ``` -Relevant contracts: +Optionally, add the following flags to prevent unbounded log growth: - - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\_blank} - - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\_blank} - - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\_blank} +```sh +--log-opt max-size=10m \ +--log-opt max-file=3 +``` -## How do I update the metadata of a wrapped token? +## Subscribe to Filtered VAAs -Because wrapped tokens are deployed and controlled by the Token Bridge program, which is under the authority of the Wormhole Guardians, there is no direct way for you to update their metadata. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes. +Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your program) can subscribe to a filtered stream of messages (VAAs). -## How do I calculate the current gas costs for Ethereum Mainnet VAA verification? +Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. -You can refer to the [core-bridge repository](https://github.com/nonergodic/core-bridge){target=\_blank} for guidance on how to calculate the current gas costs associated with verifying VAAs on Ethereum Mainnet. This repository provides up-to-date references and examples to help you gauge costs accurately. +!!! note + If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. -## How can I update my wrapped token image on Solscan? +## Data Persistence -Updating the metadata (such as the token image, name, or symbol) of a wrapped token on [Solscan](https://solscan.io/){target=\_blank} requires [contacting the Solscan team](https://solscan.io/contactus){target=\_blank} directly. Wormhole cannot make these updates for you because the wrapped token contracts are owned and controlled by the Token Bridge, not individual developers or projects. +The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. -To request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\_blank}. +The persistence layer needs to implement the appropriate interface. For example, you can check out the [Redis interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank} used by the Relayer Engine, a package that implements a client and persistence layer for messages received from a Spy subscription. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/token-bridge/get-started/ +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ --- BEGIN CONTENT --- --- -title: Get Started with Token Bridge -description: Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). -categories: Token-Bridge, Transfers +title: Core Contracts +description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. +categories: Basics --- -# Get Started with Token Bridge +# Core Contracts ## Introduction -Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. +The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. +This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - - **Manual transfer** – where you control each step - - **Automatic transfer** – where a relayer finalizes the transfer for you +## Key Functions -These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. +Key functions of the Wormhole Core Contract include the following: -## Prerequisites +- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network +- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered +- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability +- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time -Before you begin, make sure you have the following: +## How the Core Contract Works - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} - - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} +The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. -This guide uses a Solana wallet with [devnet SOL](https://faucet.solana.com/){target=\_blank} and an EVM wallet with [Sepolia ETH](https://www.alchemy.com/faucets/ethereum-sepolia){target=\_blank} for the manual transfer example, and [Avalanche Fuji](https://core.app/tools/testnet-faucet/?subnet=c&token=c){target=\_blank} and [Celo Alfajores](https://faucet.celo.org/alfajores){target=\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains. +The following describes the role of the Wormhole Core Contract in message transfers: -## Configure Your Token Transfer Environment +1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification +2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions -1. Create a new directory and initialize a Node.js project: +For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - ```bash - mkdir token-bridge - cd token-bridge - npm init -y - ``` +### Message Submission -2. Install the required dependencies: +You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - ```bash - npm install @wormhole-foundation/sdk - npm install -D tsx typescript - ``` +- `emitterAddress` - the contract which made the call to publish the message +- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) +- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page -3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities: +There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. - ```bash - touch transfer.ts helper.ts - ``` +### Message Reception -4. Set up secure access to your wallets. This guide assumes you are loading your `SOL_PRIVATE_KEY` and `EVM_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://book.getfoundry.sh/reference/cast/cast-wallet){target=\_blank}. +When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - !!! warning - If you use a `.env` file during development, add it to your `.gitignore` to exclude it from version control. Never commit private keys or mnemonics to your repository. +## Multicast -## Perform a Token Transfer +Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. -This section shows how to run manual and automatic token transfers using a shared project structure. You will define helper utilities once and reuse them across both flows. +This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -In the manual transfer, you initiate a transfer on Solana, wait for Guardian signatures, and redeem the tokens on Sepolia, giving you complete control over each step. In the automatic transfer, the relayer handles attestation and redemption, simplifying the process between EVM chains. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. -1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed: +Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. - ```ts title="helper.ts" - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, - isTokenId, - TokenId, -} from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import evm from '@wormhole-foundation/sdk/evm'; +## Next Steps -/** - * Returns a signer for the given chain using locally scoped credentials. - * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must - * be loaded securely beforehand, for example via a keystore, secrets - * manager, or environment variables (not recommended). - */ -export async function getSigner( - chain: ChainContext -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; +
    - switch (platform) { - case 'Evm': - signer = await ( - await evm() - ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!); - break; - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), SUI_MNEMONIC!); - break; - default: - throw new Error(`Unsupported platform: ${platform}`); - } +- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} + --- -/** - * Get the number of decimals for the token on the source chain. - * This helps convert a user-friendly amount (e.g., '1') into raw units. - */ -export async function getTokenDecimals( - wh: Wormhole, - token: TokenId, - chain: ChainContext -): Promise { - return isTokenId(token) - ? Number(await wh.getDecimals(token.chain, token.address)) - : chain.config.nativeTokenDecimals; -} - - ``` + Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. -2. In `transfer.ts`, add the script for your preferred transfer mode. The `automatic` flag controls transfer behavior passed to `tokenTransfer()`; set it to `false` for manual transfers and `true` for automatic transfers + [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - === "Manual Transfer" +- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - ```ts title="transfer.ts" - import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import evm from '@wormhole-foundation/sdk/evm'; -import { getSigner, getTokenDecimals } from './helper'; + --- -(async function () { - // Initialize Wormhole SDK for Solana and Sepolia on Testnet - const wh = await wormhole('Testnet', [solana, sui, evm]); + This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - // Define the source and destination chains - const sendChain = wh.getChain('Solana'); - const rcvChain = wh.getChain('Sepolia'); + [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - // Load signers and addresses from helpers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +
    +--- END CONTENT --- - // Define the token and amount to transfer - const tokenId = Wormhole.tokenId('Solana', 'native'); - const amt = '0.1'; +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ +--- BEGIN CONTENT --- +--- +title: Guardians +description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. +categories: Basics +--- - // Convert to raw units based on token decimals - const decimals = await getTokenDecimals(wh, tokenId, sendChain); - const transferAmount = amount.units(amount.parse(amt, decimals)); +## Guardian - // Set to false to require manual approval steps - const automatic = false; - const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; +Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - // Construct the transfer object - const xfer = await wh.tokenTransfer( - tokenId, - transferAmount, - source.address, - destination.address, - automatic, - undefined, - nativeGas - ); +Guardians fulfill their role in the messaging protocol as follows: - // Initiate the transfer from Solana - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); +1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians +2. Guardians combine their independent signatures to form a multisig +3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - // Wait for the signed attestation from the Guardian network - console.log('Fetching Attestation'); - const timeout = 5 * 60 * 1000; // 5 minutes - await xfer.fetchAttestation(timeout); +Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - // Redeem the tokens on Sepolia - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(destination.signer); - console.log(`Completed Transfer: `, destTxids); +## Guardian Network - process.exit(0); -})(); - ``` - - === "Automatic Transfer" +The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - ```ts title="transfer.ts" - import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import evm from '@wormhole-foundation/sdk/evm'; -import { getSigner, getTokenDecimals } from './helper'; +The Guardian Network is designed to help Wormhole deliver on five key principles: -(async function () { - // Initialize Wormhole SDK for Avalanche and Celo on Testnet - const wh = await wormhole('Testnet', [solana, sui, evm]); +- **Decentralization** - control of the network is distributed across many parties +- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability +- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network +- **Scalability** - can handle large transaction volumes and high-value transfers +- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing - // Define the source and destination chains - const sendChain = wh.getChain('Avalanche'); - const rcvChain = wh.getChain('Celo'); +The following sections explore each principle in detail. - // Load signers and addresses from helpers - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +### Decentralization - // Define the token and amount to transfer - const tokenId = Wormhole.tokenId('Avalanche', 'native'); - const amt = '0.2'; +Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. - // Convert to raw units based on token decimals - const decimals = await getTokenDecimals(wh, tokenId, sendChain); - const transferAmount = amount.units(amount.parse(amt, decimals)); +Two common approaches to decentralization have notable limitations: - // Set to false to require manual approval steps - const automatic = true; - const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n; +- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve +- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment - // Construct the transfer object - const xfer = await wh.tokenTransfer( - tokenId, - transferAmount, - source.address, - destination.address, - automatic, - undefined, - nativeGas - ); +In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. - // Initiate the transfer from Avalanche Fuji - console.log('Starting Transfer'); - const srcTxids = await xfer.initiateTransfer(source.signer); - console.log(`Started Transfer: `, srcTxids); +If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? - process.exit(0); -})(); - ``` +To answer that, consider these key constraints and design decisions: +- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system +- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen +- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security +- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants -3. Execute the script to initiate and complete the transfer: +This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. - ```bash - npx tsx transfer.ts - ``` +### Modularity - If successful, the expected output should be similar to this: +Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. -
    -npx tsx transfer.ts -Starting Transfer -Started Transfer: ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB'] - -Getting Attestation -Retrying Wormholescan:GetVaaBytes, attempt 0/900 -Retrying Wormholescan:GetVaaBytes, attempt 1/900 -Retrying Wormholescan:GetVaaBytes, attempt 2/900 - -Completing Transfer -Completed Transfer: [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ] - -
    +### Chain Agnosticism -To verify the transaction and view its details, copy the transaction hash from the output and paste it into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. -## Next Steps +### Scalability -Now that you've completed a manual multichain token transfer, explore these guides to continue building: +Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) - - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains ---- END CONTENT --- +Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. -Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/transfer-wrapped-assets/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. -Doc-Content: https://wormhole.com/docs/products/token-bridge/overview/ ---- BEGIN CONTENT --- ---- -title: Token Bridge Overview -description: With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. -categories: Token-Bridge, Transfer ---- +### Upgradeable -# Token Bridge Overview +Wormhole is designed to adapt and evolve in the following ways: -The Token Bridge is a Wormhole module for bridging wrapped tokens across various blockchain networks. Locking assets on one network and minting corresponding wrapped tokens on another facilitates secure, efficient, and composable multichain token movement. +- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set +- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model -This overview covers Token Bridge's main features, general processes, and possible next steps to begin building a cross-chain application. +These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. -## Key Features +## Next Steps -Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: +
    -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +- :octicons-book-16:{ .lg .middle } **Relayers** -## How It Works + --- -The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: + Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain + [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) -This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. +- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** -```mermaid -sequenceDiagram - participant Alice - participant Ethereum - participant GuardianNetwork - participant Solana + --- - Alice->>Ethereum: Lock ETH in Token Bridge contract - Ethereum->>GuardianNetwork: Emit transfer message - GuardianNetwork->>GuardianNetwork: Verify and sign message + Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - GuardianNetwork->>Solana: Submit signed message - Solana->>Solana: Verify message and mint wrapped ETH (WETH) + [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - Solana->>Alice: Deliver wrapped ETH on Solana -``` +
    +--- END CONTENT --- -For a more in-depth understanding of how the Token Bridge works, see the [Flow of a Transfer](/docs/products/token-bridge/concepts/transfer-flow/){target=\_blank} page. +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ +--- BEGIN CONTENT --- +--- +title: Relayers +description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. +categories: Basics +--- -## Use Cases +# Relayers -Here are key use cases that highlight the power and versatility of the Token Bridge. +This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. -- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** +Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards +There are three primary types of relayers discussed: -- **Tokenized Gaming Rewards** +- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains +- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) -- **Multichain DeFi Arbitrage** +- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms +## Fundamentals -## Next Steps +This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. -If you are looking for more guided practice, take a look at: +Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge ---- END CONTENT --- +Key characteristics of VAAs include: -Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ ---- BEGIN CONTENT --- ---- -title: Create Multichain Tokens -description: Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. ---- +- Public emission from the Guardian Network -# Create Multichain Tokens +- Authentication through signatures from the Guardian Network -## Introduction +- Verifiability by any entity or any Wormhole Core Contract -Blockchain ecosystems are becoming increasingly interconnected, with assets often needing to exist across multiple networks to maximize their utility and reach. For example, tokens created on one chain may want to expand to others to tap into broader audiences and liquidity pools. +These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. -This guide explains how to create a multichain token—a token that seamlessly bridges across blockchains using the Wormhole protocol. The process is designed to be user-friendly. With just a few steps, your token can become multichain, enabling it to be traded or used on various networks. +Keep in mind the following security considerations around relayers: -By the end of this tutorial, you'll learn: +- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks -- How to register your token for bridging -- How to create a wrapped version of your token -- How to ensure its visibility on blockchain explorers +- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly -Let’s begin with a straightforward, step-by-step process for creating a multichain token and expanding its reach. +- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain -## Register the Token on the Source Chain +## Client-Side Relaying -The first step in creating a multichain token is registering your token on its source chain. This ensures the token is prepared for bridging across blockchains. Follow these steps: +Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. -1. Open the [Portal Bridge](https://portalbridge.com/advanced-tools/#/register){target=\_blank} -2. Select the blockchain where your token is currently deployed (source chain) -3. Connect your wallet by following the on-screen instructions -4. Locate the **Asset** field and paste the token contract address -5. Click **Next** to proceed +### Key Features -![Source Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-1.webp) +- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs -## Register the Token on the Target Chain +- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure -After registering your token on the source chain, the next step is to select the target chain—the blockchain where you want the wrapped version of your token to exist. This step connects your token to its destination network. +### Implementation -1. Choose the blockchain where you want the token to be bridged (target chain) -2. Connect your wallet to the target chain -3. Click **Next** to finalize the registration process +Users themselves carry out the three steps of the cross-chain process: -![Target Chain Registration Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-2.webp) +1. Perform an action on chain A -## Send an Attestation -Attestation is a key step in the process. It verifies your token’s metadata, ensuring it is correctly recognized on the target chain’s blockchain explorer (e.g., [Etherscan](https://etherscan.io/){target=\_blank}). +2. Retrieve the resulting VAA from the Guardian Network -1. Click **Attest** to initiate the attestation process -2. Approve the transaction in your wallet when prompted +3. Perform an action on chain B using the VAA -![Send Attestation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-3.webp) +### Considerations -!!! note - - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token - - Ensure you have sufficient funds to cover transaction fees on the target chain +Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. -## Create the Wrapped Token +- Users must sign all required transactions with their own wallet -The final step is to create the wrapped token on the target chain. This token represents the original asset and enables its use within the target blockchain. +- Users must have funds to pay the transaction fees on every chain involved -1. Click **Create** to generate the wrapped token -2. Approve the transaction in your wallet when prompted +- The user experience may be cumbersome due to the manual steps involved -![Create Wrapped Token Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-4.webp) +## Custom Relayers -Upon successful creation, you will see a confirmation screen displaying key details such as the source chain, target chain, and transaction status. This helps verify that the process was completed correctly. Refer to the image below as an example: +Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. -![Confirmation Screen](/docs/images/products/token-bridge/tutorials/multichain-tokens/multichain-token-5.webp) +The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). -## Additional Steps and Recommendations +### Key Features -After creating your multichain token, there are a few optional but highly recommended steps to ensure the best experience for users interacting with your token. +- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs -### Add Your Token to the Wormhole Metadata List (Legacy) +- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more -For legacy compatibility in the [**Advanced Tools**](https://portalbridge.com/advanced-tools/){target=\_blank} section of Portal Bridge, you can request updates to your token metadata. Follow these steps: +- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application -1. Join the [Wormhole Discord server](https://discord.com/invite/wormholecrypto){target=\_blank} -2. Submit a request for metadata updates in the appropriate support channel +- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience -!!! note - These updates only apply to the **Advanced Tools** section of Portal Bridge and will not update how your token appears in other Wormhole-powered apps or on blockchain explorers like Etherscan. +### Implementation -### Update Metadata on Blockchain Explorers +A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. -It is recommended that you update your token’s metadata on blockchain explorers such as Etherscan. This includes adding details like the token logo, price, and contract verification. +### Considerations -1. Create an account on the relevant scanner and go to the [token update section](https://etherscan.io/tokenupdate){target=\_blank} (or the relevant scanner that you would like to update metadata on) -2. Copy and paste the wrapped contract address in the **Token Update Application Form** -3. Before proceeding to the next step, you will need to verify as the contract address owner on [Etherscan’s address verification tool](https://etherscan.io/verifyAddress/){target=\_blank} -4. Follow the directions to verify contract address ownership via MetaMask by reviewing the [guide on verifying address ownership](https://info.etherscan.com/how-to-verify-address-ownership/){target=\_blank} - - Given that Wormhole may be the contract owner, use the manual verification process by reaching out through the [Etherscan contact form](https://etherscan.io/contactus){target=\_blank}. The team will provide support as needed -5. Once the step above is completed, follow the [instructions to update token information](https://info.etherscan.com/how-to-update-token-information-on-token-page/){target=\_blank} ---- END CONTENT --- +Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." -Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/transfer-workflow/ ---- BEGIN CONTENT --- ---- -title: Transfer Tokens via Token Bridge Tutorial -description: Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains ---- +- Development work and hosting of relayers are required -# Complete Token Transfer Workflow +- The fee-modeling can become complex, as relayers are responsible for paying target chain fees -:simple-github: [Source code on GitHub](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank} +- Relayers are responsible for availability, and adding dependencies for the cross-chain application -## Introduction +## Wormhole Relayers -This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. +Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. -By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: +### Key Features - - EVM to EVM (e.g., Ethereum to Avalanche) - - EVM to non-EVM chains (e.g., Ethereum to Solana) - - Non-EVM to EVM chains (e.g., Sui to Avalanche) - - Non-EVM to non-EVM chains (e.g., Solana to Sui) +- **Lower operational costs** - no need to develop, host, or maintain individual relayers -Existing solutions for cross-chain transfers can be complex and inefficient, requiring multiple steps and transaction fees. However, the Token Bridge method from Wormhole simplifies the process by handling the underlying attestation, transaction validation, and message passing across blockchains. +- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface -At the end of this guide, you’ll have a fully functional setup for transferring assets across chains using Wormhole’s Token Bridge method. +### Implementation -## Prerequisites +The Wormhole relayer integration involves two key steps: -Before you begin, ensure you have the following: +- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed globally - - Native tokens (testnet or mainnet) in Solana and Sui wallets - - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees +- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA -## Supported Chains +### Considerations -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. +Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. -## Project Setup +- All computations are performed on-chain -In this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers. +- Potentially less gas-efficient compared to custom relayers -1. **Initialize the project** - start by creating a new directory for your project and initializing it with `npm`, which will create the `package.json` file for your project +- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted - ```bash - mkdir native-transfers - cd native-transfers - npm init -y - ``` +- Support may not be available for all chains -2. **Create a `.gitignore` file** - ensure your private key isn't accidentally exposed or committed to version control +## Next Steps - ```bash - echo ".env" >> .gitignore - ``` +
    -3. **Install dependencies** - install the required dependencies, including the Wormhole SDK and helper libraries +- :octicons-book-16:{ .lg .middle } **Spy** - ```bash - npm install @wormhole-foundation/sdk dotenv tsx - ``` + --- -4. **Set up environment variables** - to securely store your private key, create a `.env` file in the root of your project + Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - ```bash - touch .env - ``` + [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - Inside the `.env` file, add your private keys. +- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** - ```env - ETH_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SOL_PRIVATE_KEY="INSERT_YOUR_PRIVATE_KEY" - SUI_PRIVATE_KEY="INSERT_SUI_MNEMONIC" - ``` + --- - !!! note - Ensure your private key contains native tokens for gas on both the source and destination chains. For Sui, you must provide a mnemonic instead of a private key. + Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. -5. **Create a `helpers.ts` file** - to simplify the interaction between chains, create a file to store utility functions for fetching your private key, set up signers for different chains, and manage transaction relays + [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - 1. Create the helpers file +- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** - ```bash - mkdir -p src/helpers - touch src/helpers/helpers.ts - ``` + --- - 2. Open the `helpers.ts` file and add the following code + Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - ```typescript - import { - ChainAddress, - ChainContext, - Network, - Signer, - Wormhole, - Chain, - TokenId, - isTokenId, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import { config } from 'dotenv'; -config(); + [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) -export interface SignerStuff { - chain: ChainContext; - signer: Signer; - address: ChainAddress; -} +
    +--- END CONTENT --- -// Function to fetch environment variables (like your private key) -function getEnv(key: string): string { - const val = process.env[key]; - if (!val) throw new Error(`Missing environment variable: ${key}`); - return val; -} +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ +--- BEGIN CONTENT --- +--- +title: Spy +description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. +categories: Basics +--- -// Signer setup function for different blockchain platforms -export async function getSigner( - chain: ChainContext, - gasLimit?: bigint -): Promise<{ - chain: ChainContext; - signer: Signer; - address: ChainAddress; -}> { - let signer: Signer; - const platform = chain.platform.utils()._platform; +# Spy - switch (platform) { - case 'Solana': - signer = await ( - await solana() - ).getSigner(await chain.getRpc(), getEnv('SOL_PRIVATE_KEY')); - break; - case 'Evm': - const evmSignerOptions = gasLimit ? { gasLimit } : {}; - signer = await ( - await evm() - ).getSigner( - await chain.getRpc(), - getEnv('ETH_PRIVATE_KEY'), - evmSignerOptions - ); - break; - case 'Sui': - signer = await ( - await sui() - ).getSigner(await chain.getRpc(), getEnv('SUI_MNEMONIC')); - break; - case 'Aptos': - signer = await ( - await aptos() - ).getSigner(await chain.getRpc(), getEnv('APTOS_PRIVATE_KEY')); - break; - default: - throw new Error('Unsupported platform: ' + platform); - } +In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. - return { - chain, - signer: signer as Signer, - address: Wormhole.chainAddress(chain.chain, signer.address()), - }; -} +The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. -export async function getTokenDecimals< - N extends 'Mainnet' | 'Testnet' | 'Devnet' ->( - wh: Wormhole, - token: TokenId, - sendChain: ChainContext -): Promise { - return isTokenId(token) - ? Number(await wh.getDecimals(token.chain, token.address)) - : sendChain.config.nativeTokenDecimals; -} -
    - ``` +This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. - - **`getEnv`** - this function fetches environment variables like your private key from the `.env` file - - **`getSigner`** - based on the chain you're working with (EVM, Solana, Sui, etc.), this function retrieves a signer for that specific platform. The signer is responsible for signing transactions and interacting with the blockchain. It securely uses the private key stored in your `.env` file - - **`getTokenDecimals`** - this function fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers +## Key Features -## Check and Create Wrapped Tokens +- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time +- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest +- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services +- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity +- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure -Before tokens are transferred across chains, it should be checked whether a wrapped version exists on the destination chain. If not, an attestation must be generated to wrap it so it can be sent and received on that chain. +## Integrator Use Case -In this section, you'll create a script that automates this process by checking whether Arbitrum Sepolia has a wrapped version on Base Sepolia and registering it if needed. +The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. -### Configure the Wrapped Token Script +This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. -1. **Create the `create-wrapped.ts` file** - set up the script file that will handle checking and wrapping tokens in the `src` directory +## Observable Message Categories - ```bash - mkdir -p src/scripts - touch src/scripts/create-wrapped.ts - ``` +A Spy can access the following categories of messages shared over the gossip protocol: -2. **Open `create-wrapped.ts` and import the required modules** - import the necessary SDK modules to interact with Wormhole, EVM, Solana, and Sui chains, as well as helper functions for signing and sending transactions +- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - ```typescript - import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; - ``` + - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support +- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` + - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events - !!! note - You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet. +- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status -4. **Configure transfer parameters** - specify Arbitrum Sepolia as the source chain and Base Sepolia as the destination, retrieve the token ID from the source chain for transfer, and set the gas limit (optional) + - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network - ```typescript - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); - ``` +## Additional Resources -5. **Set up the destination chain signer** - the signer authorizes transactions, such as submitting the attestation +
    - ```typescript - - ``` +- :octicons-code-16:{ .lg .middle } **Spy Source Code** -6. **Check if the token is wrapped on the destination chain** - verify if the token already exists as a wrapped asset before creating an attestation + --- - ```typescript - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } - ``` + To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. - If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-bridge/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated. + [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} -7. **Set up the source chain signer** - the signer creates and submits the attestation transaction +- :octicons-code-16:{ .lg .middle } **Alternative Implementation** - ```typescript - - ``` + --- -8. **Create an attestation transaction** - generate and send an attestation for the token on the source chain to register it on the destination chain, then save the transaction ID to verify the attestation in the next step + Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. - ```typescript - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); + [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); - ``` +- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** -9. **Retrieve the signed VAA** - once the attestation transaction is confirmed, use `parseTransaction(txid)` to extract Wormhole messages, then retrieve the signed VAA from the messages. The timeout defines how long to wait for the VAA before failure + --- - ```typescript - console.log('Parsed Messages:', msgs); + For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } - ``` + [:custom-arrow: Explore Queries](/docs/build/queries/overview/) -10. **Submit the attestation on the destination chain** - submit the signed VAA using `submitAttestation(vaa, recipient)` to create the wrapped token on the destination chain, then send the transaction and await confirmation +
    - ```typescript - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); +## Next Steps - const tsx = await signSendWait(destChain, subAttestation, destSigner); - ``` +
    -11. **Wait for the wrapped asset to be available** - poll until the wrapped token is available on the destination chain +- :octicons-code-16:{ .lg .middle } **Run a Spy** - ```typescript - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } + --- - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` + Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - If the token is not found, it logs a message and retries after a short delay. Once the wrapped asset is detected, its address is returned. + [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} -??? code "Complete script" - ```typescript - import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { inspect } from 'util'; -import { getSigner } from '../helpers/helpers'; +- :octicons-code-16:{ .lg .middle } **Use Queries** -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); + --- - // Define the source and destination chains - const srcChain = wh.getChain('ArbitrumSepolia'); - const destChain = wh.getChain('BaseSepolia'); - const token = await srcChain.getNativeWrappedTokenId(); - const gasLimit = BigInt(2_500_000); + For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - // Destination chain signer setup - const { signer: destSigner } = await getSigner(destChain, gasLimit); - const tbDest = await destChain.getTokenBridge(); + [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) - try { - const wrapped = await tbDest.getWrappedAsset(token); - console.log( - `Token already wrapped on ${destChain.chain}. Skipping attestation.` - ); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.log( - `No wrapped token found on ${destChain.chain}. Proceeding with attestation.` - ); - } +
    +--- END CONTENT --- - // Source chain signer setup - const { signer: origSigner } = await getSigner(srcChain); +Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ +--- BEGIN CONTENT --- +--- +title: VAAs +description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. +categories: Basics +--- - // Create an attestation transaction on the source chain - const tbOrig = await srcChain.getTokenBridge(); - const attestTxns = tbOrig.createAttestation( - token.address, - Wormhole.parseAddress(origSigner.chain(), origSigner.address()) - ); +# Verified Action Approvals - const txids = await signSendWait(srcChain, attestTxns, origSigner); - console.log('txids: ', inspect(txids, { depth: null })); - const txid = txids[0]!.txid; - console.log('Created attestation (save this): ', txid); +Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. - // Retrieve the Wormhole message ID from the attestation transaction - const msgs = await srcChain.parseTransaction(txid); - console.log('Parsed Messages:', msgs); +[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. - const timeout = 25 * 60 * 1000; - const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout); - if (!vaa) { - throw new Error( - 'VAA not found after retries exhausted. Try extending the timeout.' - ); - } +The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. - console.log('Token Address: ', vaa.payload.token.address); +VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. - // Submit the attestation on the destination chain - console.log('Attesting asset on destination chain...'); +The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. + +The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. - const subAttestation = tbDest.submitAttestation( - vaa, - Wormhole.parseAddress(destSigner.chain(), destSigner.address()) - ); +## VAA Format - const tsx = await signSendWait(destChain, subAttestation, destSigner); - console.log('Transaction hash: ', tsx); +The basic VAA consists of header and body components described as follows: - // Poll for the wrapped asset until it's available - async function waitForIt() { - do { - try { - const wrapped = await tbDest.getWrappedAsset(token); - return { chain: destChain.chain, address: wrapped }; - } catch (e) { - console.error('Wrapped asset not found yet. Retrying...'); - } - console.log('Waiting before checking again...'); - await new Promise((r) => setTimeout(r, 2000)); - } while (true); - } +- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far + - `version` ++"byte"++ - the VAA Version + - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing + - `len_signatures` ++"u8"++ - the number of signatures stored + - `signatures` ++"[]signature"++ - the collection of Guardian signatures - console.log('Wrapped Asset: ', await waitForIt()); -})().catch((e) => console.error(e)); - ``` + Where each `signature` is: -### Run the Wrapped Token Creation + - `index` ++"u8"++ - the index of this Guardian in the Guardian set + - `signature` ++"[65]byte"++ - the ECDSA signature -Once the script is ready, execute it with: +- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages + - `timestamp` ++"u32"++ - the timestamp of the block this message was published in + - `nonce` ++"u32"++ + - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message + - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract + - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter + - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter + - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on -```bash -npx tsx src/scripts/create-wrapped.ts -``` +The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level -If the token is already wrapped, the script exits. Otherwise, it generates an attestation and submits it. Once complete, you’re ready to transfer tokens across chains. +The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. -## Token Transfers +Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. -In this section, you'll create a script to transfer native tokens across chains using Wormhole's Token Bridge method. The script will handle the transfer of Sui native tokens to Solana, demonstrating the seamless cross-chain transfer capabilities of the Wormhole SDK. Since both chains are non-EVM compatible, you'll need to manually handle the attestation and finalization steps. +## Consistency and Finality -### Configure Transfer Details +The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. -Before initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains. +Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. -1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains +## Signatures - ```bash - touch src/scripts/native-transfer.ts - ``` +The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. -2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files +```js +// hash the bytes of the body twice +digest = keccak256(keccak256(body)) +// sign the result +signature = ecdsa_sign(digest, key) +``` - ```typescript - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; - ``` +!!!tip "Hash vs. double hash" + Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. + + For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. -3. **Initialize the Wormhole SDK** - initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support +## Payload Types - ```typescript - const wh = await wormhole('Testnet', [evm, solana, sui]); - ``` +Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). -4. **Set up source and destination chains** - specify the source chain (Sui) and the destination chain (Solana) using the `getChain` method. This allows us to define where to send the native tokens and where to receive them +### Token Transfer - ```typescript - const rcvChain = wh.getChain('Solana'); - ``` +Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. -5. **Configure the signers** - use the `getSigner` function to retrieve the signers responsible for signing transactions on the respective chains. This ensures that transactions are correctly authorized on both the source and destination chains +Transferring tokens from the sending chain to the destination chain requires the following steps: - ```typescript - const destination = await getSigner(rcvChain); - ``` +1. Lock the token on the sending chain +2. The sending chain emits a message as proof the token lockup is complete +3. The destination chain receives the message confirming the lockup event on the sending chain +4. The token is minted on the destination chain -6. **Define the token to transfer** - specify the native token on the source chain (Sui in this example) by creating a `TokenId` object +The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - ```typescript - - ``` +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `fee` ++"u256"++ - portion of amount paid to a relayer -7. **Define the transfer amount** - the amount of native tokens to transfer is specified. In this case, we're transferring 1 unit +This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - ```typescript - - ``` +Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. -8. **Set transfer mode** - specify that the transfer should be manual by setting `automatic = false`. This means you will need to handle the attestation and finalization steps yourself +### Attestation - ```typescript - - ``` +While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - !!! note - Automatic transfers are only supported for EVM chains. For non-EVM chains like Solana and Sui, you must manually handle the attestation and finalization steps. - -9. **Define decimals** - fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function +To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - ```typescript - - ``` +The message format for token attestation is as follows: -10. **Perform the token transfer and exit the process** - initiate the transfer by calling the `tokenTransfer` function, which we’ll define in the next step. This function takes an object containing all required details for executing the transfer, including the `source` and `destination` chains, `token`, `mode`, and transfer `amount` +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation +- `token_address` ++"[32]byte"++ - address of the originating token contract +- `token_chain` ++"u16"++ - chain ID of the originating token +- `decimals` ++"u8"++ - number of decimals this token should have +- `symbol` ++"[32]byte"++ - short name of asset +- `name` ++"[32]byte"++ - full name of asset - ```typescript - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); - ``` +#### Attestation Tips - Finally, we use `process.exit(0);` to close the script once the transfer completes +Be aware of the following considerations when working with attestations: - ```typescript - })(); - ``` +- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters -### Token Transfer Logic +- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes -This section defines the `tokenTransfer` function, which manages the core steps for cross-chain transfer execution. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain. +- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm -#### Defining the Token Transfer Function +- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 -The `tokenTransfer` function initiates and manages the transfer process, handling all necessary steps to move tokens across chains with the Wormhole SDK. This function uses types from the SDK and our `helpers.ts` file to ensure chain compatibility. +- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer -```typescript -wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic -import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; +### Token Transfer with Message -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); +The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); +- **`fee` field** - replaced with the `from_address` field +- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); +- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message +- `amount` ++"u256"++ - amount of tokens being transferred +- `token_address` ++"u8[32]"++ - address on the source chain +- `token_chain` ++"u16"++ - numeric ID for the source chain +- `to` ++"u8[32]"++ - address on the destination chain +- `to_chain` ++"u16"++ - numeric ID for the destination chain +- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain +- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific - // Define the amount of tokens to transfer - const amt = '1'; +### Governance - // Set automatic transfer to false for manual transfer - const automatic = false; +Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); +#### Action Structure - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); +Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: - process.exit(0); -})(); +- `module` ++"u8[32]"++ - contains a right-aligned module identifier +- `action` ++"u8"++ - predefined governance action to execute +- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains +- `args` ++"any"++ - arguments to the action -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); +Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +```js +module: 0x0000000000000000000000000000000000000000000000000000436f7265 +action: 1 +chain: 1 +new_contract: 0x348567293758957162374959376192374884562522281937446234828323 +``` - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +#### Actions - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); +The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); +- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} +- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - -``` +## Lifetime of a Message -#### Steps to Transfer Tokens +Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. -The `tokenTransfer` function consists of several key steps to facilitate the cross-chain transfer. Let’s break down each step: +With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. -1. **Initialize the transfer object** - the `tokenTransfer` function begins by creating a `TokenTransfer` object, `xfer`, which tracks the state of the transfer process and provides access to relevant methods for each transfer step +1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians +2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA +3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step - ```typescript - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); - ``` +![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) -2. **Estimate transfer fees and validate amount** - we obtain a fee quote for the transfer before proceeding. This step is significant in automatic mode (`automatic = true`), where the quote will include additional fees for relaying +## Next Steps - ```typescript - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +
    - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; - ``` +- :octicons-book-16:{ .lg .middle } **Guardians** -3. **Submit the transaction to the source chain** - initiate the transfer on the source chain by submitting the transaction using `route.source.signer`, starting the token transfer process + --- - ```typescript - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - ``` + Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - - **`srcTxids`** - the resulting transaction IDs are printed to the console. These IDs can be used to track the transfer’s progress on the source chain and [Wormhole network](https://wormholescan.io/#/?network=Testnet){target=\_blank} + [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - ???- note "How Cross-Chain Transfers Work in the Background" - When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background: +- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** - - **Token lock or burn** - tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount - - **VAA creation** - Wormhole’s network of Guardians generates a Verifiable Action Approval (VAA)—a signed proof of the transaction, which ensures it’s recognized across chains - - **Tracking the transfer** - the returned transaction IDs allow you to track the transfer's progress both on the source chain and within Wormhole’s network - - **Redemption on destination** - once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer + --- - This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain. + Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. -4. **Wait for the attestation** - retrieve the Wormhole attestation (VAA), which serves as cryptographic proof of the transfer. In manual mode, you must wait for the VAA before redeeming the transfer on the destination chain + [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) - ```typescript - - ``` +
    +--- END CONTENT --- -5. **Complete the transfer on the destination chain** - redeem the VAA on the destination chain to finalize the transfer +Doc-Content: https://wormhole.com/docs/protocol/introduction/ +--- BEGIN CONTENT --- +--- +title: Introduction to Wormhole +description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. +categories: Basics +--- - ```typescript - console.log(`Completed Transfer: `, destTxids); - ``` +# Introduction to Wormhole -??? code "Complete script" - ```typescript - import { - Chain, - Network, - Wormhole, - amount, - wormhole, - TokenId, - TokenTransfer, -} from '@wormhole-foundation/sdk'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers'; +In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. -(async function () { - const wh = await wormhole('Testnet', [evm, solana, sui]); +Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. - // Set up source and destination chains - const sendChain = wh.getChain('Sui'); - const rcvChain = wh.getChain('Solana'); +Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. - // Get signer from local key but anything that implements - const source = await getSigner(sendChain); - const destination = await getSigner(rcvChain); +![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) - // Shortcut to allow transferring native gas token - const token = Wormhole.tokenId(sendChain.chain, 'native'); +!!! note + The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. - // Define the amount of tokens to transfer - const amt = '1'; +Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. - // Set automatic transfer to false for manual transfer - const automatic = false; +This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. - // Used to normalize the amount to account for the tokens decimals - const decimals = await getTokenDecimals(wh, token, sendChain); +## What Problems Does Wormhole Solve? - // Perform the token transfer if no recovery transaction ID is provided - const xfer = await tokenTransfer(wh, { - token, - amount: amount.units(amount.parse(amt, decimals)), - source, - destination, - automatic, - }); +Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. - process.exit(0); -})(); +Critical problems Wormhole addresses include: -async function tokenTransfer( - wh: Wormhole, - route: { - token: TokenId; - amount: bigint; - source: SignerStuff; - destination: SignerStuff; - automatic: boolean; - payload?: Uint8Array; - } -) { - // Token Transfer Logic - // Create a TokenTransfer object to track the state of the transfer over time - const xfer = await wh.tokenTransfer( - route.token, - route.amount, - route.source.address, - route.destination.address, - route.automatic ?? false, - route.payload - ); +- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks +- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications +- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions - const quote = await TokenTransfer.quoteTransfer( - wh, - route.source.chain, - route.destination.chain, - xfer.transfer - ); +## What Does Wormhole Offer? - if (xfer.transfer.automatic && quote.destinationToken.amount < 0) - throw 'The amount requested is too low to cover the fee and any native gas requested.'; +Wormhole provides a suite of tools and protocols that support a wide range of use cases: - // Submit the transactions to the source chain, passing a signer to sign any txns - console.log('Starting transfer'); - const srcTxids = await xfer.initiateTransfer(route.source.signer); - console.log(`Source Trasaction ID: ${srcTxids[0]}`); - console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`); +- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) +- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} +- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently - // Wait for the VAA to be signed and ready (not required for auto transfer) - console.log('Getting Attestation'); - await xfer.fetchAttestation(60_000); +## What Isn't Wormhole? - // Redeem the VAA on the dest chain - console.log('Completing Transfer'); - const destTxids = await xfer.completeTransfer(route.destination.signer); - console.log(`Completed Transfer: `, destTxids); -} - - ``` +- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself +- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge -### Run the Native Token Transfer +## Use Cases of Wormhole -Now that you’ve set up the project and defined the transfer logic, you can execute the script to transfer native tokens from the Sui chain to Solana. You can use `tsx` to run the TypeScript file directly: +Consider the following examples of potential applications enabled by Wormhole: -```bash -npx tsx src/scripts/native-transfer.ts -``` +- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum -This initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana). +## Explore -You can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\_blank}. +Discover more about the Wormhole ecosystem, components, and protocols: -## Resources +- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole -If you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in [Wormhole's demo GitHub repository](https://github.com/wormhole-foundation/demo-basic-ts-sdk/){target=\_blank}. The repository includes all the example scripts and configurations needed to perform native token cross-chain transfers, including manual, automatic, and partial transfers using the Wormhole SDK. +## Demos -## Conclusion +Demos offer more realistic implementations than tutorials: -You've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the Token Bridge method. This guide took you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains like Sui and Solana. +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository +- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs -The same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains. + + +!!! note + Wormhole Integration Complete? + + Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! + + **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** + +## Supported Blockchains + +Wormhole supports a growing number of blockchains. + +text/supported-networks.md --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/architecture/ +Doc-Content: https://wormhole.com/docs/protocol/security/ --- BEGIN CONTENT --- --- -title: Architecture -description: Overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers. +title: Security +description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. categories: Basics --- -# Architecture +# Security -## Overview +## Core Security Assumptions -Wormhole has several noteworthy components. Before discussing each component in depth, this page will provide an overview of how the major pieces fit together. +At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} +- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator +- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs +- Any Signed VAA can be verified as authentic by the Core Contract of any other chain +- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem -The preceding diagram outlines the end-to-end flow of multichain communication through Wormhole's architecture, which is described as follows: +In summary: -1. **Source chain** - a source contract emits a message by interacting with the [Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain, which publishes the message in the blockchain's transaction logs -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate these messages and sign them to produce [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain relayers or applications fetch the VAA and relay it to the target chain -4. **Target chain** - on the target chain, the message is consumed by the appropriate contract. This contract interacts with the Wormhole Core Contract to verify the VAA and execute the intended multichain operation. +- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** +- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on +- You can expand your contract and chain dependencies as you see fit - The flow from the relayer to the target chain involves an entry point contract, which could vary based on the use case: +Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. - - In some applications, the target contract acts as the entry point and performs verification via the Core Contract - - In products like the Token Bridge, the Token Bridge contract itself interacts with the Core Contract +## Guardian Network -## On-Chain Components +Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol -- **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication -- **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract +### Governance -## Off-Chain Components +Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. -- **Guardian Network** - validators that exist in their own P2P network. Guardians observe and validate the messages emitted by the Core Contract on each supported chain to produce VAAs (signed messages) -- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank}** - one of 19 validators in the Guardian Network that contributes to the VAA multisig -- **[Spy](/docs/protocol/infrastructure/spy/){target=\_blank}** - a daemon that subscribes to messages published within the Guardian Network. A Spy can observe and forward network traffic, which helps scale up VAA distribution -- **[API](https://docs.wormholescan.io/){target=\_blank}** - a REST server to retrieve details for a VAA or the Guardian Network -- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}** - Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract -- **[Relayer](/docs/protocol/infrastructure/relayer/){target=\_blank}** - any off-chain process that relays a VAA to the target chain - - **Wormhole relayers** - a decentralized relayer network that delivers messages that are requested on-chain via the Wormhole relayer contract - - **Custom relayers** - relayers that only handle VAAs for a specific protocol or multichain application. They can execute custom logic off-chain, reducing gas costs and increasing multichain compatibility. Currently, multichain application developers are responsible for developing and hosting custom relayers +This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. -## Next Steps +Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. -
    +All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. -- :octicons-book-16:{ .lg .middle } **Core Contracts** +Via governance, the Guardians can: - --- +- Change the current Guardian set +- Expand the Guardian set +- Upgrade ecosystem contract implementations - Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization. +The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. - [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/) +## Monitoring -- :octicons-tools-16:{ .lg .middle } **Core Messaging** +A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. - --- +Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. - Follow the guides in this section to work directly with the building blocks of Wormhole messaging, Wormhole-deployed relayers and Core Contracts, to send, receive, validate, and track multichain messages. +Guardians monitor: - [:custom-arrow: Build with Core Messaging](/docs/products/messaging/guides/wormhole-relayers/) +- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue +- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains +- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators -
    ---- END CONTENT --- +## Asset Layer Protections -Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-relayer/ ---- BEGIN CONTENT --- ---- -title: Run a Relayer -description: Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. -categories: Relayers ---- +One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. -# Run a Custom Relayer +To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. -## Introduction +In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. -Relayers play a crucial role in cross-chain communication, ensuring that messages are transferred seamlessly between different blockchains. While Wormhole relayers provide a reliable way to handle these transfers, they might not always meet every application's unique requirements. +## Open Source -Custom relayers address these limitations by offering tailored solutions that cater to the distinct needs of your application. Developing a custom relayer gives you complete control over message processing, delivery mechanisms, and integration with existing systems. This customization allows for optimized performance and the ability to implement specific features that Wormhole-deployed relayers might not support. +Wormhole builds in the open and is always open source. -A custom relayer might be as simple as an in-browser process that polls the API for the availability of a VAA after submitting a transaction and delivers it to the target chain. It might also be implemented with a Spy coupled with some daemon listening for VAAs from a relevant chain ID and emitter, then taking action when one is observed. +- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** +- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** +- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** -This guide teaches you how to set up and configure a custom relayer for efficient message handling. You'll start by understanding how to uniquely identify a VAA using its emitter address, sequence ID, and chain ID. Then, you'll explore the Relayer Engine, a package that provides a framework for building custom relayers, and learn how to fetch and handle VAAs using the Wormhole SDK. +## Audits -## Get Started with a Custom Relayer +Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: -To start building a custom relayer, it's essential to grasp the components you'll be managing as part of your relaying service. Your relayer must be capable of retrieving and delivering VAAs. +- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} +- [Neodyme](https://neodyme.io/en/){target=\_blank} +- [Kudelski](https://kudelskisecurity.com/){target=\_blank} +- [OtterSec](https://osec.io/){target=\_blank} +- [Certik](https://www.certik.com/){target=\_blank} +- [Hacken](https://hacken.io/){target=\_blank} +- [Zellic](https://www.zellic.io/){target=\_blank} +- [Coinspect](https://www.coinspect.com/){target=\_blank} +- [Halborn](https://www.halborn.com/){target=\_blank} +- [Cantina](https://cantina.xyz/welcome){target=\_blank} -
    - ![Custom relayer](/docs/images/protocol/infrastructure-guides/run-relayer/relayer-1.webp) -
    The off-chain components outlined in blue must be implemented.
    -
    +All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. -### How to Uniquely Identify a VAA +## Bug Bounties -Regardless of the environment, to get the VAA you intend to relay, you need: +Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. -- The `emitter` address -- The `sequence` ID of the message you're interested in -- The `chainId` for the chain that emitted the message +Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. -With these three components, you're able to uniquely identify a VAA and process it. +If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. -## Use the Relayer Engine +For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. -The [`relayer-engine`](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} is a package that provides the structure and a starting point for a custom relayer. +## Learn More -With the Relayer Engine, a developer can write specific logic for filtering to receive only the messages they care about. +The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +--- END CONTENT --- -Once a Wormhole message is received, the developer may apply additional logic to parse custom payloads or submit the Verifiable Action Approvals (VAA) to one or many destination chains. +Doc-Content: https://wormhole.com/docs/tools/cli/get-started/ +--- BEGIN CONTENT --- +--- +title: Wormhole CLI +description: Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. +categories: Solidity-SDK, Typescript-SDK +--- -To use the Relayer Engine, a developer may specify how to relay Wormhole messages for their app using an idiomatic Express/Koa middleware-inspired API, then let the library handle all the details. +# Wormhole CLI -### Install the Relayer Engine +This tool is a command-line interface to Wormhole, allowing you to perform various actions, such as querying a transaction's status or submitting token transfers. -First, install the `relayer-engine` package with your favorite package manager: +## Installation + +Clone the repository and change directories to the appropriate directory: ```bash -npm i @wormhole-foundation/relayer-engine +git clone https://github.com/wormhole-foundation/wormhole && +cd wormhole/clients/js ``` -### Get Started with the Relayer Engine +Build and install the CLI tool: -In the following example, you'll: +```bash +make install +``` -1. Set up a `StandardRelayerApp`, passing configuration options for our relayer -2. Add a filter to capture only those messages our app cares about, with a callback to do _something_ with the VAA once received -3. Start the relayer app +This installs two binaries, `worm-fetch-governance` and `worm` on your `$PATH`. To use `worm`, set up `$HOME/.wormhole/.env` with your private keys, based on `.env.sample` in this folder. -```typescript -import { - Environment, - StandardRelayerApp, - StandardRelayerContext, -} from '@wormhole-foundation/relayer-engine'; -import { CHAIN_ID_SOLANA } from '@certusone/wormhole-sdk'; +## Usage -(async function main() { - // Initialize relayer engine app and pass relevant config options - const app = new StandardRelayerApp( - Environment.TESTNET, - // Other app specific config options can be set here for things - // like retries, logger, or redis connection settings - { - name: 'ExampleRelayer', - } - ); +You can interact with the Wormhole CLI by typing `worm` and including the `command` and any necessary subcommands and parameters. - // Add a filter with a callback that will be invoked - // on finding a VAA that matches the filter - app.chain(CHAIN_ID_SOLANA).address( - // Emitter address on Solana - 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', - // Callback function to invoke on new message - async (ctx, next) => { - const vaa = ctx.vaa; - const hash = ctx.sourceTxHash; - console.log( - `Got a VAA with sequence: ${vaa.sequence} from with txhash: ${hash}` - ); - } - ); +| Command | Description | +|--------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| +| `worm aptos INSERT_COMMAND` | Aptos utilities | +| `worm edit-vaa INSERT_COMMAND` | Edits or generates a VAA | +| `worm evm INSERT_COMMAND` | EVM utilities | +| `worm generate INSERT_COMMAND` | Generate VAAs (Devnet and Testnet only) | +| `worm info INSERT_COMMAND` | Contract, chain, RPC, and address information utilities | +| `worm near INSERT_NETWORK, INSERT_ACCOUNT` | NEAR utilities | +| `worm parse INSERT_VAA` | Parse a VAA (can be in either hex or base64 format) | +| `worm recover INSERT_DIGEST INSERT_SIGNATURE` | Recover an address from a signature | +| `worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH` | Prints information about the automatic delivery initiated on the specified network, chain, and transaction hash | +| `worm submit INSERT_VAA` | Execute a VAA | +| `worm sui INSERT_COMMAND` | Sui utilities | +| `worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK` | Transfers a token | +| `worm verify-vaa INSERT_VAA, INSERT_NETWORK` | Verifies a VAA by querying the Core Contract on Ethereum | - // Add and configure any other middleware here +You can also refer to the below options, available with all `worm` commands: - // Start app. Blocks until unrecoverable error or process is stopped - await app.listen(); -})(); - +```bash +Options: + --help Show help [boolean] + --version Show version number [boolean] ``` -The first meaningful line instantiates the `StandardRelayerApp`, a subclass of the `RelayerApp` with standard defaults. +### Subcommands -```typescript -export class StandardRelayerApp< - ContextT extends StandardRelayerContext = StandardRelayerContext, -> extends RelayerApp { - // ... - constructor(env: Environment, opts: StandardRelayerAppOpts) { -``` +??? interface "Aptos" + ```bash + worm aptos INSERT_COMMAND -The only field you pass in the `StandardRelayerAppOpts` is the name to help identify log messages and reserve a namespace in Redis. +Commands: + worm aptos init-token-bridge Init token bridge contract + worm aptos init-wormhole Init Wormhole core contract + worm aptos deploy Deploy an Aptos package + worm aptos deploy-resource Deploy an Aptos package using a + resource account + worm aptos send-example-message Send example message + + worm aptos derive-resource-account Derive resource account address + + worm aptos derive-wrapped-address Derive wrapped coin type + + worm aptos hash-contracts Hash contract bytecodes for upgrade + worm aptos upgrade Perform upgrade after VAA has been + submitted + worm aptos migrate Perform migration after contract + upgrade + worm aptos faucet Request money from the faucet for a + given account + worm aptos start-validator Start a local aptos validator -??? code "`StandardRelayerAppOpts`" +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` - Other options can be passed to the `StandardRelayerApp` constructor to configure the app further. +??? interface "Edit VAA" + ```bash + worm edit-vaa INSERT_COMMAND - ```typescript - wormholeRpcs?: string[]; // List of URLs from which to query missed VAAs -concurrency?: number; // How many concurrent requests to make for workflows -spyEndpoint?: string; // The hostname and port of our Spy -logger?: Logger; // A custom Logger -privateKeys?: Partial<{ [k in ChainId]: any[]; }>; // A set of keys that can be used to sign and send transactions -tokensByChain?: TokensByChain; // The token list we care about -workflows?: { retries: number; }; // How many times to retry a given workflow -providers?: ProvidersOpts; // Configuration for the default providers -fetchSourceTxhash?: boolean; // whether or not to get the original transaction ID/hash -// Redis config -redisClusterEndpoints?: ClusterNode[]; -redisCluster?: ClusterOptions; -redis?: RedisOptions; +Options: + --help Show help [boolean] + --version Show version number [boolean] + -v, --vaa vaa in hex format [string] [required] + -n, --network Network + [required] [choices: "mainnet", "testnet", "devnet"] + --guardian-set-index, --gsi guardian set index [number] + --signatures, --sigs comma separated list of signatures [string] + --wormscanurl, --wsu url to wormscan entry for the vaa that + includes signatures [string] + --wormscan, --ws if specified, will query the wormscan entry + for the vaa to get the signatures [boolean] + --emitter-chain-id, --ec emitter chain id to be used in the vaa + [number] + --emitter-address, --ea emitter address to be used in the vaa[string] + --nonce, --no nonce to be used in the vaa [number] + --sequence, --seq sequence number to be used in the vaa[string] + --consistency-level, --cl consistency level to be used in the vaa + [number] + --timestamp, --ts timestamp to be used in the vaa in unix + seconds [number] + -p, --payload payload in hex format [string] + --guardian-secret, --gs Guardian's secret key [string] ``` -The next meaningful line in the example adds a filter middleware component. This middleware will cause the relayer app to request a subscription from the Spy for any VAAs that match the criteria and invoke the callback with the VAA. - -If you'd like your program to subscribe to `multiple` chains and addresses, you can call the same method several times or use the `multiple` helper. +??? interface "EVM" + ```bash + worm evm INSERT_COMMAND -```typescript -app.multiple( - { - [CHAIN_ID_SOLANA]: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe', - [CHAIN_ID_ETH]: ['0xabc1230000000...', '0xdef456000...'], - }, - myCallback -); -``` +Commands: + worm evm address-from-secret Compute a 20 byte eth address from a 32 + byte private key + worm evm storage-update Update a storage slot on an EVM fork + during testing (anvil or hardhat) + worm evm chains Return all EVM chains + worm evm info Query info about the on-chain state of + the contract + worm evm hijack Override the guardian set of the core + bridge contract during testing (anvil + or hardhat) + worm evm start-validator Start a local EVM validator -The last line in the simple example runs `await app.listen()`, which starts the relayer engine. Once started, the Relayer Engine issues subscription requests to the Spy and begins any other workflows (e.g., tracking missed VAAs). +Options: + --help Show help [boolean] + --version Show version number [boolean] + --rpc RPC endpoint [string] + ``` -This will run until the process is killed or encounters an unrecoverable error. To gracefully shut down the relayer, call `app.stop()`. +??? interface "Generate" + ```bash + worm generate INSERT_COMMAND -The source code for this example is available in the [`relayer-engine` repository](https://github.com/wormhole-foundation/relayer-engine/blob/main/examples/simple/src/app.ts){target=\_blank}. +Commands: + worm generate registration Generate registration VAA + worm generate upgrade Generate contract upgrade VAA + worm generate attestation Generate a token attestation VAA + worm generate recover-chain-id Generate a recover chain ID VAA + worm generate Sets the default delivery provider + set-default-delivery-provider for the Wormhole Relayer contract -## Start Background Processes +Options: + --help Show help [boolean] + --version Show version number [boolean] + -g, --guardian-secret Guardians' secret keys (CSV) [string] [required] + ``` -!!! note - These processes _must_ be running for the relayer app below to work. +??? interface "Info" + ```bash + worm info INSERT_COMMAND -Next, you must start a Spy to listen for available VAAs published on the Guardian network. You also need a persistence layer. This example uses Redis. +Commands: + worm info chain-id Print the wormhole chain ID integer + associated with the specified chain + name + worm info contract Print contract address + + worm info emitter
    Print address in emitter address + format + worm info origin
    Print the origin chain and address + of the asset that corresponds to the + given chain and address. + worm info registrations Print chain registrations + + worm info rpc Print RPC address + worm info wrapped Print the wrapped address on the + target chain that corresponds with + the specified origin chain and + address. -More details about the Spy are available in the [Spy Documentation](/docs/protocol/infrastructure/spy){target=\_blank}. +Options: + --help Show help [boolean] + --version Show version number [boolean]
    + ``` -### Wormhole Network Spy +??? interface "NEAR" + ```bash + worm near INSERT_COMMAND -For our relayer app to receive messages, a local Spy must be running that watches the Guardian network. Our relayer app will receive updates from this Spy. +Commands: + worm near contract-update Submit a contract update using our specific + APIs + worm near deploy Submit a contract update using near APIs -=== "Mainnet Spy" +Options: + --help Show help [boolean] + --version Show version number [boolean] + -m, --module Module to query [choices: "Core", "NFTBridge", "TokenBridge"] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + --account Near deployment account [string] [required] + --attach Attach some near [string] + --target Near account to upgrade [string] + --mnemonic Near private keys [string] + --key Near private key [string] + -r, --rpc Override default rpc endpoint url [string] + ``` +??? interface "Parse" ```bash - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env mainnet - ``` + worm parse INSERT_VAA -=== "Testnet Spy" +Positionals: + vaa vaa [string] - ```bash - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env testnet +Options: + --help Show help [boolean] + --version Show version number [boolean] ``` -### Redis Persistence +??? interface "Recover" + ```bash + worm recover INSERT_DIGEST INSERT_SIGNATURE -!!! note - While you're using [Redis](https://redis.io/docs/latest/develop/get-started/){target=\_blank} here, the persistence layer can be swapped out for some other database by implementing the appropriate [interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank}. +Positionals: + digest digest [string] + signature signature [string] -A Redis instance must also be available to persist job data for fetching VAAs from the Spy. +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` -```bash -docker run --rm -p 6379:6379 --name redis-docker -d redis -``` - -## Use the Wormhole SDK - -!!! note - The example below uses the legacy [`@certusone/wormhole-sdk`](https://www.npmjs.com/package/@certusone/wormhole-sdk){target=\_blank}, which is still supported and used in the Relayer Engine but is no longer actively maintained. - - For most use cases, it is recommend to use the latest [`@wormhole-foundation/sdk`](https://www.npmjs.com/package/@wormhole-foundation/sdk){target=\_blank}. - -You can also use the Wormhole SDK to poll the Guardian RPC until a signed VAA is ready using the SDK's `getSignedVAAWithRetry` function. - -```ts -import { - getSignedVAAWithRetry, - parseVAA, - CHAIN_ID_SOLANA, - CHAIN_ID_ETH, -} from '@certusone/wormhole-sdk'; - -const RPC_HOSTS = [ - /* ...*/ -]; - -async function getVAA( - emitter: string, - sequence: string, - chainId: number -): Promise { - // Wait for the VAA to be ready and fetch it from the guardian network - const { vaaBytes } = await getSignedVAAWithRetry( - RPC_HOSTS, - chainId, - emitter, - sequence - ); - return vaaBytes; -} - -const vaaBytes = await getVAA('INSERT_EMITTER_ADDRESS', 1, CHAIN_ID_ETH); - -``` - -Once you have the VAA, the delivery method is chain-dependent. +??? interface "Status" + ```bash + worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH -=== "EVM" +Positionals: + network Network [choices: + 'mainnet', + 'testnet', + 'devnet'] + chain Source chain + [choices: + 'unset', + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + tx Source transaction hash [string] - On EVM chains, the bytes for the VAA can be passed directly as an argument to an ABI method. +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` - ```ts - // Set up eth wallet -const ethProvider = new ethers.providers.StaticJsonRpcProvider( - 'INSERT_RPC_URL' -); -const ethWallet = new ethers.Wallet('INSERT_PRIVATE_KEY', ethProvider); +??? interface "Submit" + ```bash + worm submit INSERT_VAA -// Create client to interact with our target app -const ethHelloWorld = HelloWorld__factory.connect( - 'INSERT_CONTRACT_ADDRESS', - ethWallet -); +Positionals: + vaa vaa [string] -// Invoke the receiveMessage on the ETH contract and wait for confirmation -const receipt = await ethHelloWorld - .receiveMessage(vaaBytes) - .then((tx: ethers.ContractTransaction) => tx.wait()) - .catch((msg: any) => { - console.error(msg); - return null; - }); +Options: + --help Show help [boolean] + --version Show version number [boolean] + -c, --chain chain name +[choices: 'unset', + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + -n, --network Network + [required] + [choices: + 'mainnet', + 'testnet', + 'devnet'] + -a, --contract-address Contract to submit VAA to (override config) [string] + --rpc RPC endpoint [string] + --all-chains, --ac Submit the VAA to all chains except for the origin + chain specified in the payload + [boolean] [default: false] ``` -=== "Solana" - - On Solana, the VAA is first posted to the core bridge, and then a custom transaction is prepared to process and validate the VAA. +??? interface "Sui" + ```bash + worm sui INSERT_COMMAND - ```ts - import { CONTRACTS } from '@certusone/wormhole-sdk'; +Commands: + worm sui build-coin Build wrapped coin and dump bytecode. -export const WORMHOLE_CONTRACTS = CONTRACTS[NETWORK]; -export const CORE_BRIDGE_PID = new PublicKey(WORMHOLE_CONTRACTS.solana.core); + Example: + worm sui build-coin -d 8 -v V__0_1_1 -n + testnet -r + "https://fullnode.testnet.sui.io:443" + worm sui deploy Deploy a Sui package + worm sui init-example-message-app Initialize example core message app + worm sui init-token-bridge Initialize token bridge contract + worm sui init-wormhole Initialize wormhole core contract + worm sui publish-example-message Publish message from example app via + core bridge + worm sui setup-devnet Setup devnet by deploying and + initializing core and token bridges and + submitting chain registrations. + worm sui objects Get owned objects by owner + worm sui package-id Get package ID from State object ID + worm sui tx Get transaction details -// First, post the VAA to the core bridge -await postVaaSolana( - connection, - wallet.signTransaction, - CORE_BRIDGE_PID, - wallet.key(), - vaaBytes -); +Options: + --help Show help [boolean] + --version Show version number [boolean] + ``` -const program = createHelloWorldProgramInterface(connection, programId); -const parsed = isBytes(wormholeMessage) - ? parseVaa(wormholeMessage) - : wormholeMessage; +??? interface "Transfer" + ```bash + worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK -const ix = program.methods - .receiveMessage([...parsed.hash]) - .accounts({ - payer: new PublicKey(payer), - config: deriveConfigKey(programId), - wormholeProgram: new PublicKey(wormholeProgramId), - posted: derivePostedVaaKey(wormholeProgramId, parsed.hash), - foreignEmitter: deriveForeignEmitterKey(programId, parsed.emitterChain), - received: deriveReceivedKey( - programId, - parsed.emitterChain, - parsed.sequence - ), - }) - .instruction(); - -const transaction = new Transaction().add(ix); -const { blockhash } = await connection.getLatestBlockhash(commitment); -transaction.recentBlockhash = blockhash; -transaction.feePayer = new PublicKey(payerAddress); - -const signed = await wallet.signTxn(transaction); -const txid = await connection.sendRawTransaction(signed); - -await connection.confirmTransaction(txid); - ``` ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure-guides/run-spy/ ---- BEGIN CONTENT --- ---- -title: Run a Spy -description: Learn how to run a Spy locally to listen for and forward messages (Verifiable Action Approvals, or VAAs) published on the Wormhole network. ---- - -# Run a Spy - -## Introduction - -The Spy is a lightweight component in the Wormhole infrastructure designed to listen for and forward messages (Verifiable Action Approvals (VAAs)) published on the Wormhole network. Running a Spy locally allows developers to subscribe to a filtered stream of these messages, facilitating the development of custom relayers or other integrations with Wormhole. - -For a more comprehensive understanding of the Spy and its role within the Wormhole ecosystem, refer to the [Spy Documentation](/docs/protocol/infrastructure/spy/){target=\_blank}. - -## How to Start a Spy - -To start a Spy locally, run the following Docker command: - -=== "Mainnet" - - ```sh - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env mainnet - ``` - -=== "Testnet" - - ```sh - docker run --pull=always --platform=linux/amd64 \ - -p 7073:7073 \ - --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \ - spy \ - --nodeKey /node.key \ - --spyRPC "[::]:7073" \ - --env testnet - ``` - -If you want to run the Spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image. - -Optionally, add the following flags to skip any VAAs with invalid signatures: - -=== "Mainnet" - - ```sh - --ethRPC https://eth.drpc.org - --ethContract 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B - ``` - -=== "Testnet" - - ```sh - --ethRPC https://sepolia.drpc.org/ - --ethContract 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 - ``` - -Optionally, add the following flags to prevent unbounded log growth: - -```sh ---log-opt max-size=10m \ ---log-opt max-file=3 -``` - -## Subscribe to Filtered VAAs - -Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your program) can subscribe to a filtered stream of messages (VAAs). - -Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. - -!!! note - If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. - -## Data Persistence - -The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. - -The persistence layer needs to implement the appropriate interface. For example, you can check out the [Redis interface](https://github.com/wormhole-foundation/relayer-engine/blob/main/relayer/storage/redis-storage.ts){target=\_blank} used by the Relayer Engine, a package that implements a client and persistence layer for messages received from a Spy subscription. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/core-contracts/ ---- BEGIN CONTENT --- ---- -title: Core Contracts -description: Discover Wormhole's Core Contracts, which enable multichain communication with message sending, receiving, and multicast features for efficient synchronization. -categories: Basics ---- - -# Core Contracts - -## Introduction - -The Wormhole Core Contract is deployed across each supported blockchain network. This contract is a fundamental component of the Wormhole interoperability protocol and acts as the foundational layer enabling secure and efficient multichain messaging. All multichain applications either interact directly with the Core Contract or with another contract that does. - -This page summarizes the key functions of the Core Contract and outlines how the Core Contract works. - -## Key Functions - -Key functions of the Wormhole Core Contract include the following: - -- **Multichain messaging** - standardizes and secures the format of messages to facilitate consistent communication for message transfer between Wormhole-connected blockchain networks, allowing developers to leverage the unique features of each network -- **Verification and validation** - verifies and validates all VAAs received on the target chain by confirming the Guardian signature to ensure the message is legitimate and has not been manipulated or altered -- **Guardian Network coordination** - coordinates with Wormhole's Guardian Network to facilitate secure, trustless communication across chains and ensure that only validated interactions are processed to enhance the protocol's overall security and reliability -- **Event emission for monitoring** - emits events for every multichain message processed, allowing for network activity monitoring like tracking message statuses, debugging, and applications that can react to multichain events in real time - -## How the Core Contract Works - -The Wormhole Core Contract is central in facilitating secure and efficient multichain transactions. It enables communication between different blockchain networks by packaging transaction data into standardized messages, verifying their authenticity, and ensuring they are executed correctly on the destination chain. - -The following describes the role of the Wormhole Core Contract in message transfers: - -1. **Message submission** - when a user initiates a multichain transaction, the Wormhole Core Contract on the source chain packages the transaction data into a standardized message payload and submits it to the Guardian Network for verification -2. **Guardian verification** - the Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **Message reception and execution** - on the target chain, the Wormhole Core Contract receives the verified message, checks the Guardians' signatures, and executes the corresponding actions like minting tokens, updating states, or calling specific smart contract functions - -For a closer look at how messages flow between chains and all of the components involved, you can refer to the [Architecture Overview](/docs/protocol/architecture/) page. - -### Message Submission - -You can send multichain messages by calling a function against the source chain Core Contract, which then publishes the message. Message publishing strategies can differ by chain; however, generally, the Core Contract posts the following items to the blockchain logs: - -- `emitterAddress` - the contract which made the call to publish the message -- `sequenceNumber` - a unique number that increments for every message for a given emitter (and implicitly chain) -- `consistencyLevel`- the level of finality to reach before the Guardians will observe and attest the emitted event. This is a defense against reorgs and rollbacks since a transaction, once considered "final," is guaranteed not to have the state changes it caused rolled back. Since different chains use different consensus mechanisms, each one has different finality assumptions, so this value is treated differently on a chain-by-chain basis. See the options for finality for each chain in the [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\_blank} reference page - -There are no fees to publish a message except when publishing on Solana, but this is subject to change in the future. - -### Message Reception - -When you receive a multichain message on the target chain Core Contract, you generally must parse and verify the [components of a VAA](/docs/protocol/infrastructure/vaas#vaa-format){target=\_blank}. Receiving and verifying a VAA ensures that the Guardian Network properly attests to the message and maintains the integrity and authenticity of the data transmitted between chains. - -## Multicast - -Multicast refers to simultaneously broadcasting a single message or transaction across different blockchains with no destination address or chain for the sending and receiving functions. VAAs attest that "this contract on this chain said this thing." Therefore, VAAs are multicast by default and will be verified as authentic on any chain where they are used. - -This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. - -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. - -Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. - -## Next Steps - -
    - -- :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)** - - --- - - Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication. - - [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/) - -- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts** - - --- - - This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts. - - [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/guardians/ ---- BEGIN CONTENT --- ---- -title: Guardians -description: Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. -categories: Basics ---- - -## Guardian - -Wormhole relies on a set of 19 distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as Guardians. The current Guardian set can be seen in the [Dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank}. - -Guardians fulfill their role in the messaging protocol as follows: - -1. Each Guardian observes messages and signs the corresponding payloads in isolation from the other Guardians -2. Guardians combine their independent signatures to form a multisig -3. This multisig represents proof that a majority of the Wormhole network has observed and agreed upon a state - -Wormhole refers to these multisigs as [Verifiable Action Approvals](/docs/protocol/infrastructure/vaas/){target=\_blank} (VAAs). - -## Guardian Network - -The Guardian Network functions as Wormhole's decentralized oracle, ensuring secure, cross-chain interoperability. Learning about this critical element of the Wormhole ecosystem will help you better understand the protocol. - -The Guardian Network is designed to help Wormhole deliver on five key principles: - -- **Decentralization** - control of the network is distributed across many parties -- **Modularity** - independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability -- **Chain agnosticism** - supports EVM, Solana, and other blockchains without relying on a single network -- **Scalability** - can handle large transaction volumes and high-value transfers -- **Upgradeable** - can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing - -The following sections explore each principle in detail. - -### Decentralization - -Decentralization remains the core concern for interoperability protocols. Earlier solutions were fully centralized, and even newer models often rely on a single entity or just one or two actors, creating low thresholds for collusion or failure. - -Two common approaches to decentralization have notable limitations: - -- **Proof-of-Stake (PoS)** - while PoS is often seen as a go-to model for decentralization, it's not well-suited for a network that verifies many blockchains and doesn't run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve -- **Zero-Knowledge Proofs (ZKPs)** - ZKPs offer a trustless and decentralized approach, but the technology is still early-stage. On-chain verification is often too computationally expensive—especially on less capable chains—so a multisig-based fallback is still required for practical deployment - -In the current De-Fi landscape, most major blockchains are secured by a small group of validator companies. Only a limited number of companies worldwide have the expertise and capital to run high-performance validators. - -If a protocol could unite many of these top validator companies into a purpose-built consensus mechanism designed for interoperability, it would likely offer better performance and security than a token-incentivized network. The key question is: how many of them could Wormhole realistically involve? - -To answer that, consider these key constraints and design decisions: - -- **Threshold signatures allow flexibility, but** - with threshold signatures, in theory, any number of validators could participate. However, threshold signatures are not yet widely supported across blockchains. Verifying them is expensive and complex, especially in a chain-agnostic system -- **t-Schnorr multisig is more practical** - Wormhole uses [t-Schnorr multisig](https://en.wikipedia.org/wiki/Schnorr_signature){target=\_blank}, which is broadly supported and relatively inexpensive to verify. However, verification costs scale linearly with the number of signers, so the size of the validator set needs to be carefully chosen -- **19 validators is the optimal tradeoff** - a set of 19 participants presents a practical compromise between decentralization and efficiency. With a two-thirds consensus threshold, only 13 signatures must be verified on-chain—keeping gas costs reasonable while ensuring strong security -- **Security through reputation, not tokens** - Wormhole relies on a network of established validator companies instead of token-based incentives. These 19 Guardians are among the most trusted operators in the industry—real entities with a track record, not anonymous participants - -This forms the foundation for a purpose-built Proof-of-Authority (PoA) consensus model, where each Guardian has an equal stake. As threshold signatures gain broader support, the set can expand. Once ZKPs become widely viable, the network can evolve into a fully trustless system. - -### Modularity - -Wormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([relayers](/docs/protocol/infrastructure/relayer/){target=\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others. - -### Chain Agnosticism - -Today, Wormhole supports a broader range of ecosystems than any other interoperability protocol because it uses simple tech (t-schnorr signatures), an adaptable, heterogeneous relayer model, and a robust validator network. Wormhole can expand to new ecosystems as quickly as a [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} can be developed for the smart contract runtime. - -### Scalability - -Wormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events. - -Every Guardian must run a full node for every blockchain in the ecosystem. This requirement can be computationally heavy to set up; however, once all the full nodes are running, the Guardian Network's actual computation needs become lightweight. - -Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself. - -### Upgradeable - -Wormhole is designed to adapt and evolve in the following ways: - -- **Guardian Set expansion** – future updates may introduce threshold signatures to allow for more Guardians in the set -- **ZKP integration** - as Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model - -These principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing. - -## Next Steps - -
    - -- :octicons-book-16:{ .lg .middle } **Relayers** - - --- - - Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. - - [:custom-arrow: Learn About Relayers](/docs/protocol/infrastructure/relayer/) - -- :octicons-tools-16:{ .lg .middle } **Query Guardian Data** - - --- - - Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/relayer/ ---- BEGIN CONTENT --- ---- -title: Relayers -description: Discover the role of relayers in the Wormhole network, including client-side, custom, and Wormhole-deployed types, for secure cross-chain communication. -categories: Basics ---- - -# Relayers - -This page provides a comprehensive guide to relayers within the Wormhole network, describing their role, types, and benefits in facilitating cross-chain processes. - -Relayers in the Wormhole context are processes that deliver [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} to their destination, playing a crucial role in Wormhole's security model. They can't compromise security, only availability, and act as delivery mechanisms for VAAs without the capacity to tamper with the outcome. - -There are three primary types of relayers discussed: - -- **Client-side relaying** - a cost-efficient, no-backend-infrastructure approach relying on user-facing front ends. It provides a simple solution, although it can complicate the user experience due to the manual steps involved - -- **Custom relayers** - backend components that handle parts of the cross-chain process, offering a smoother user experience and allowing off-chain calculations to reduce gas costs. These relayers could operate through direct listening to the Guardian Network (Spy relaying) - -- **Wormhole-deployed relayers** - a decentralized relayer network that can deliver arbitrary VAAs, reducing the developer's need to develop, host, or maintain relayers. However, they require all calculations to be done on-chain and might be less gas-efficient - -## Fundamentals - -This section highlights the crucial principles underpinning the operation and handling of relayers within the Wormhole network. - -Relayers are fundamentally trustless entities within the network, meaning while they don't require your trust to operate, you also shouldn't trust them implicitly. Relayers function as delivery mechanisms, transporting VAAs from their source to their destination. - -Key characteristics of VAAs include: - -- Public emission from the Guardian Network - -- Authentication through signatures from the Guardian Network - -- Verifiability by any entity or any Wormhole Core Contract - -These characteristics mean anyone can pick up a VAA and deliver it anywhere, but no one can alter the VAA content without invalidating the signatures. - -Keep in mind the following security considerations around relayers: - -- **Trusting information** - it is crucial not to trust information outside your contract or a VAA. Relying on information from a relayer could expose you to input attacks - -- **Gas optimization** - using relayers to perform trustless off-chain computation to pass into the destination contract can optimize gas costs but also risk creating attack vectors if not used correctly - -- **Deterministic by design** - the design of a relayer should ensure a single, deterministic way to process messages in your protocol. Relayers should have a "correct" implementation, mirroring "crank turner" processes used elsewhere in blockchain - -## Client-Side Relaying - -Client-side relaying relies on user-facing front ends, such as a webpage or a wallet, to complete the cross-chain process. - -### Key Features - -- **Cost-efficiency** - users only pay the transaction fee for the second transaction, eliminating any additional costs - -- **No backend infrastructure** - the process is wholly client-based, eliminating the need for a backend relaying infrastructure - -### Implementation - -Users themselves carry out the three steps of the cross-chain process: - -1. Perform an action on chain A - -2. Retrieve the resulting VAA from the Guardian Network - -3. Perform an action on chain B using the VAA - -### Considerations - -Though simple, this type of relaying is generally not recommended if your aim is a highly polished user experience. It can, however, be useful for getting a Minimum Viable Product (MVP) up and running. - -- Users must sign all required transactions with their own wallet - -- Users must have funds to pay the transaction fees on every chain involved - -- The user experience may be cumbersome due to the manual steps involved - -## Custom Relayers - -Custom relayers are purpose-built components within the Wormhole protocol, designed to relay messages for specific applications. They can perform off-chain computations and can be customized to suit a variety of use cases. - -The main method of setting up a custom relayer is by listening directly to the Guardian Network via a [Spy](/docs/protocol/infrastructure/spy/). - -### Key Features - -- **Optimization** - capable of performing trustless off-chain computations which can optimize gas costs - -- **Customizability** - allows for specific strategies like batching, conditional delivery, multi-chain deliveries, and more - -- **Incentive structure** - developers have the freedom to design an incentive structure suitable for their application - -- **Enhanced UX** - the ability to retrieve a VAA from the Guardian Network and perform an action on the target chain using the VAA on behalf of the user can simplify the user experience - -### Implementation - -A plugin relayer to make the development of custom relayers easier is available in the [main Wormhole repository](https://github.com/wormhole-foundation/wormhole/tree/main/relayer){target=\_blank}. This plugin sets up the basic infrastructure for relaying, allowing developers to focus on implementing the specific logic for their application. - -### Considerations - -Remember, despite their name, custom relayers still need to be considered trustless. VAAs are public and can be submitted by anyone, so developers shouldn't rely on off-chain relayers to perform any computation considered "trusted." - -- Development work and hosting of relayers are required - -- The fee-modeling can become complex, as relayers are responsible for paying target chain fees - -- Relayers are responsible for availability, and adding dependencies for the cross-chain application - -## Wormhole Relayers - -Wormhole relayers are a component of a decentralized network in the Wormhole protocol. They facilitate the delivery of VAAs to recipient contracts compatible with the standard relayer API. - -### Key Features - -- **Lower operational costs** - no need to develop, host, or maintain individual relayers - -- **Simplified integration** - because there is no need to run a relayer, integration is as simple as calling a function and implementing an interface - -### Implementation - -The Wormhole relayer integration involves two key steps: - -- **Delivery request** - request delivery from the ecosystem Wormhole relayer contract - -- **Relay reception** - implement a [`receiveWormholeMessages`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/bacbe82e6ae3f7f5ec7cdcd7d480f1e528471bbb/src/interfaces/IWormholeReceiver.sol#L44-L50){target=\_blank} function within their contracts. This function is invoked upon successful relay of the VAA - -### Considerations - -Developers should note that the choice of relayers depends on their project's specific requirements and constraints. Wormhole relayers offer simplicity and convenience but limit customization and optimization opportunities compared to custom relayers. - -- All computations are performed on-chain - -- Potentially less gas-efficient compared to custom relayers - -- Optimization features like conditional delivery, batching, and off-chain calculations might be restricted - -- Support may not be available for all chains - -## Next Steps - -
    - -- :octicons-book-16:{ .lg .middle } **Spy** - - --- - - Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. - - [:custom-arrow: Learn More About the Spy](/docs/protocol/infrastructure/spy/) - -- :octicons-book-16:{ .lg .middle } **Build with Wormhole Relayers** - - --- - - Learn how to use Wormhole-deployed relayer configurations for seamless cross-chain messaging between contracts on different EVM blockchains without off-chain deployments. - - [:custom-arrow: Get Started with Wormhole Relayers](/docs/products/messaging/guides/wormhole-relayers/) - -- :octicons-book-16:{ .lg .middle } **Run a Custom Relayer** - - --- - - Learn how to build and configure your own off-chain custom relaying solution to relay Wormhole messages for your applications using the Relayer Engine. - - [:custom-arrow: Get Started with Custom Relayers](/docs/protocol/infrastructure-guides/run-relayer/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/spy/ ---- BEGIN CONTENT --- ---- -title: Spy -description: Discover Wormhole's Spy daemon, which subscribes to gossiped messages in the Guardian Network, including VAAs and Observations, with setup instructions. -categories: Basics ---- - -# Spy - -In Wormhole's ecosystem, the _Spy_ is a daemon, a continuously running background process that monitors messages within the Guardian Network. Unlike Guardians, a Spy doesn't perform validation; instead, it serves as an interface for observing the network's message traffic, enabling applications and users to access live data transmitted over Wormhole. - -The primary purpose of a Spy is to subscribe to the gossiped messages across the Guardian Network, tracking key message types that allow integrators and applications to monitor real-time network activity without directly engaging in consensus operations. - -This page provides a comprehensive guide to where the Spy fits within the Wormhole network, describing the key features and role in facilitating multichain processes. - -## Key Features - -- **Real-time monitoring of Wormhole messages** - the Spy allows users to observe Wormhole messages as they are published across supported chains in near real-time -- **Filterable and observable message streams** - users can filter message streams by chain, emitter, and other criteria, making it easier to track specific contracts or categories of interest -- **Integration-friendly event streaming** - the Spy exposes gRPC and WebSocket interfaces, making it easy to integrate message observation into custom tooling, dashboards, or indexing services -- **Support for multiple message protocols** - it can observe messages from different Wormhole messaging protocols (Token Bridge, CCTP, NTT, etc.), providing broad coverage of cross-chain activity -- **Lightweight and infrastructure-ready** - the Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure - -## Integrator Use Case - -The Spy provides a valuable mechanism for integrators to observe real-time network activity in the Guardian Network without directly engaging in validation or consensus. By running a Spy, integrators can track multichain events and message flows — such as VAAs, observations, and Guardian heartbeats — to monitor network activity essential to their applications. - -This monitoring capability is especially beneficial for applications that need immediate insights into multichain data events. Integrators can run a Spy to ensure their applications are promptly informed of message approvals, observations, or Guardian liveness signals, supporting timely and responsive app behavior without additional overhead on network resources. - -## Observable Message Categories - -A Spy can access the following categories of messages shared over the gossip protocol: - -- [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} - packets of multichain data - - - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification - -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - - - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events - -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - - - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network - -## Additional Resources - -
    - -- :octicons-code-16:{ .lg .middle } **Spy Source Code** - - --- - - To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub. - - [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\_blank} - -- :octicons-code-16:{ .lg .middle } **Alternative Implementation** - - --- - - Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy. - - [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon) - -- :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries** - - --- - - For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) - -
    - -## Next Steps - -
    - -- :octicons-code-16:{ .lg .middle } **Run a Spy** - - --- - - Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs). - - [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/){target=\_blank} - -- :octicons-code-16:{ .lg .middle } **Use Queries** - - --- - - For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/infrastructure/vaas/ ---- BEGIN CONTENT --- ---- -title: VAAs -description: Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. -categories: Basics ---- - -# Verified Action Approvals - -Verified Action Approvals (VAAs) are Wormhole's core messaging primitive. They are packets of cross-chain data emitted whenever a cross-chain application contract interacts with the Core Contract. - -[Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} validate messages emitted by contracts before sending them to the target chain. Once a majority of Guardians agree the message is valid, they sign a keccak256 hash of the message body. - -The message is wrapped up in a structure called a VAA, which combines the message with the Guardian signatures to form a proof. - -VAAs are uniquely indexed by the (`emitter_chain`, `emitter_address`, `sequence`) tuple. To obtain a VAA, one can query the [Wormholescan API](https://docs.wormholescan.io/){target=\_blank} with this information. - -The `sequence` field depends on the final ordering of blocks on the emitter chain. When a lower consistency level is chosen (i.e., not waiting for finality), there is a chance that chain reorganizations could lead to multiple, different VAAs appearing for what looks like the “same” message on the user side. - -The tuple (`emitter_chain`, `emitter_address`, `sequence`) can only be considered unique if the chain does not undergo a reorg and the block containing the message has effectively reached finality. However, there is always a small chance of an extended reorg that could invalidate or alter a previously emitted sequence number. - -## VAA Format - -The basic VAA consists of header and body components described as follows: - -- **Header** - holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far - - `version` ++"byte"++ - the VAA Version - - `guardian_set_index` ++"u32"++ - indicates which Guardian set is signing - - `len_signatures` ++"u8"++ - the number of signatures stored - - `signatures` ++"[]signature"++ - the collection of Guardian signatures - - Where each `signature` is: - - - `index` ++"u8"++ - the index of this Guardian in the Guardian set - - `signature` ++"[65]byte"++ - the ECDSA signature - -- **Body** - _deterministically_ derived from an on-chain message. Any two Guardians processing the same message must derive the same resulting body to maintain a one-to-one relationship between VAAs and messages to avoid double-processing messages - - `timestamp` ++"u32"++ - the timestamp of the block this message was published in - - `nonce` ++"u32"++ - - `emitter_chain` ++"u16"++ - the id of the chain that emitted the message - - `emitter_address` ++"[32]byte"++ - the contract address (Wormhole formatted) that called the Core Contract - - `sequence` ++"u64"++ - the auto-incrementing integer that represents the number of messages published by this emitter - - `consistency_level` ++"u8"++ - the consistency level (finality) required by this emitter - - `payload` ++"[]byte"++ - arbitrary bytes containing the data to be acted on - -The deterministic nature of the body is only strictly true once the chain's state is finalized. If a reorg occurs, and a transaction that previously appeared in block X is replaced by block Y, Guardians observing different forks may generate different VAAs for what the emitter contract believes is the same message. This scenario is less likely once a block is sufficiently buried, but it can still happen if you choose a faster (less finalized) consistency level - -The body contains relevant information for entities, such as contracts or other systems, that process or utilize VAAs. When a function like `parseAndVerifyVAA` is called, the body is returned, allowing verification of the `emitterAddress` to determine if the VAA originated from a trusted contract. - -Because VAAs have no destination, they are effectively multicast. Any Core Contract on any chain in the network will verify VAAs as authentic. If a VAA has a specific destination, relayers are responsible for appropriately completing that delivery. - -## Consistency and Finality - -The consistency level determines whether Guardians wait for a chain's final commitment state or issue a VAA sooner under less-final conditions. This choice is especially relevant for blockchains without instant finality, where the risk of reorganization remains until a block is deeply confirmed. - -Guardian watchers are specialized processes that monitor each blockchain in real-time. They enforce the selected consistency level by deciding whether enough commitment has been reached before signing and emitting a VAA. Some chains allow only one commitment level (effectively final), while others let integrators pick between near-final or fully finalized states. Choosing a faster option speeds up VAA production but increases reorg risk. A more conservative option takes longer but reduces the likelihood of rollback. - -## Signatures - -The body of the VAA is hashed twice with `keccak256` to produce the signed digest message. - -```js -// hash the bytes of the body twice -digest = keccak256(keccak256(body)) -// sign the result -signature = ecdsa_sign(digest, key) -``` - -!!!tip "Hash vs. double hash" - Different implementations of the ECDSA signature validation may apply a keccak256 hash to the message passed, so care must be taken to pass the correct arguments. - - For example, the [Solana secp256k1 program](https://docs.solanalabs.com/runtime/programs#secp256k1-program){target=\_blank} will hash the message passed. In this case, the argument for the message should be a single hash of the body, not the twice-hashed body. - -## Payload Types - -Different applications built on Wormhole may specify a format for the payloads attached to a VAA. This payload provides information on the target chain and contract so it can take action (e.g., minting tokens to a receiver address). - -### Token Transfer - -Many bridges use a lockup/mint and burn/unlock mechanism to transfer tokens between chains. Wormhole's generic message-passing protocol handles the routing of lock and burn events across chains to ensure Wormhole's Token Bridge is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract. - -Transferring tokens from the sending chain to the destination chain requires the following steps: - -1. Lock the token on the sending chain -2. The sending chain emits a message as proof the token lockup is complete -3. The destination chain receives the message confirming the lockup event on the sending chain -4. The token is minted on the destination chain - -The message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `1` for a token transfer -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `fee` ++"u256"++ - portion of amount paid to a relayer - -This structure contains everything the destination chain needs to learn about a lockup event. Once the destination chain receives this payload, it can mint the corresponding asset. - -Note that the destination chain is agnostic regarding how the tokens on the sending side were locked. They could have been burned by a mint or locked in a custody account. The protocol relays the event once enough Guardians have attested to its existence. - -### Attestation - -While the destination chain can trust the message from the sending chain to inform it of token lockup events, it has no way of verifying the correct token is locked up. To solve this, the Token Bridge supports token attestation. - -To create a token attestation, the sending chain emits a message containing metadata about a token, which the destination chain may use to preserve the name, symbol, and decimal precision of a token address. - -The message format for token attestation is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `2` for an attestation -- `token_address` ++"[32]byte"++ - address of the originating token contract -- `token_chain` ++"u16"++ - chain ID of the originating token -- `decimals` ++"u8"++ - number of decimals this token should have -- `symbol` ++"[32]byte"++ - short name of asset -- `name` ++"[32]byte"++ - full name of asset - -#### Attestation Tips - -Be aware of the following considerations when working with attestations: - -- Attestations use a fixed-length byte array to encode UTF8 token name and symbol data. Because the byte array is fixed length, the data contained may truncate multibyte Unicode characters - -- When sending an attestation VAA, it is recommended to send the longest UTF8 prefix that doesn't truncate a character and then right-pad it with zero bytes - -- When parsing an attestation VAA, it is recommended to trim all trailing zero bytes and convert the remainder to UTF-8 via any lossy algorithm - -- Be mindful that different on-chain systems may have different VAA parsers, resulting in different names/symbols on different chains if the string is long or contains invalid UTF8 - -- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, the Token Bridge requires an attestation for each token transfer - -### Token Transfer with Message - -The Token Transfer with Message data structure is identical to the token-only data structure, except for the following: - -- **`fee` field** - replaced with the `from_address` field -- **`payload` field** - is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior - -This VAA type was previously known as Contract Controlled Transfer and is also sometimes referred to as a `payload3` message. The Token Transfer with Message data sructure is as follows: - -- `payload_id` ++"u8"++ - the ID of the payload. This should be set to `3` for a token transfer with message -- `amount` ++"u256"++ - amount of tokens being transferred -- `token_address` ++"u8[32]"++ - address on the source chain -- `token_chain` ++"u16"++ - numeric ID for the source chain -- `to` ++"u8[32]"++ - address on the destination chain -- `to_chain` ++"u16"++ - numeric ID for the destination chain -- `from_address` ++"u8[32]"++ - address that called the Token Bridge on the source chain -- `payload` ++"[]byte"++ - message, arbitrary bytes, app-specific - -### Governance - -Governance VAAs don't have a `payload_id` field like the preceding formats. Instead, they trigger an action in the deployed contracts (for example, an upgrade). - -#### Action Structure - -Governance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields: - -- `module` ++"u8[32]"++ - contains a right-aligned module identifier -- `action` ++"u8"++ - predefined governance action to execute -- `chain` ++"u16"++ - chain the action is targeting. This should be set to `0` for all chains -- `args` ++"any"++ - arguments to the action - -Below is an example message containing a governance action triggering a code upgrade to the Solana Core Contract. The module field here is a right-aligned encoding of the ASCII Core, represented as a 32-byte hex string. - -```js -module: 0x0000000000000000000000000000000000000000000000000000436f7265 -action: 1 -chain: 1 -new_contract: 0x348567293758957162374959376192374884562522281937446234828323 -``` - -#### Actions - -The meaning of each numeric action is pre-defined and documented in the Wormhole design documents. For each application, the relevant definitions can be found via these links: - -- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\_blank} -- [Token Bridge governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\_blank} - -## Lifetime of a Message - -Anyone can submit a VAA to the target chain. Guardians typically don't perform this step to avoid transaction fees. Instead, applications built on top of Wormhole can acquire a VAA via the Guardian RPC and submit it in a separate flow. - -With the concepts now defined, it is possible to illustrate a full flow for message passing between two chains. The following stages demonstrate each step of processing that the Wormhole network performs to route a message. - -1. **A message is emitted by a contract running on Chain A** - any contract can emit messages, and the Guardians are programmed to observe all chains for these events. Here, the Guardians are represented as a single entity to simplify the graphics, but the observation of the message must be performed individually by each of the 19 Guardians -2. **Signatures are aggregated** - Guardians independently observe and sign the message. Once enough Guardians have signed the message, the collection of signatures is combined with the message and metadata to produce a VAA -3. **VAA submitted to target chain** - the VAA acts as proof that the Guardians have collectively attested the existence of the message payload. The VAA is submitted (or relayed) to the target chain to be processed by a receiving contract and complete the final step - -![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp) - -## Next Steps - -
    - -- :octicons-book-16:{ .lg .middle } **Guardians** - - --- - - Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems. - - [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/) - -- :octicons-tools-16:{ .lg .middle } **Wormhole Relayer** - - --- - - Explore this guide to using Wormhole-deployed relayers to send and receive messages using VAAs. - - [:custom-arrow: Build with Wormhole Relayer](/docs/products/messaging/guides/wormhole-relayers/) - -
    ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/protocol/introduction/ ---- BEGIN CONTENT --- ---- -title: Introduction to Wormhole -description: Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. -categories: Basics ---- - -# Introduction to Wormhole +Options: + --help Show help [boolean] + --version Show version number [boolean] + --src-chain source chain [required] [choices: + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + --dst-chain destination chain + [required] [choices: + 'solana', + 'ethereum', + 'terra', + 'bsc', + 'polygon', + 'avalanche', + 'oasis', + 'algorand', + 'aurora', + 'fantom', + 'karura', + 'acala', + 'klaytn', + 'celo', + 'near', + 'moonbeam', + 'neon', + 'terra2', + 'injective', + 'osmosis', + 'sui', + 'aptos', + 'arbitrum', + 'optimism', + 'gnosis', + 'pythnet', + 'xpla', + 'btc', + 'base', + 'sei', + 'rootstock', + 'scroll', + 'mantle', + 'blast', + 'xlayer', + 'linea', + 'berachain', + 'seievm', + 'wormchain', + 'cosmoshub', + 'evmos', + 'kujira', + 'neutron', + 'celestia', + 'stargaze', + 'seda', + 'dymension', + 'provenance', + 'sepolia', + 'arbitrum_sepolia', + 'base_sepolia', + 'optimism_sepolia', + 'holesky', + 'polygon_sepolia'] + --dst-addr destination address [string] [required] + --token-addr token address [string] [default: native token] + --amount token amount [string] [required] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + --rpc RPC endpoint [string] + ``` -In the rapidly evolving landscape of blockchain technology, interoperability between different blockchains remains a significant challenge. Developers often face hurdles in creating applications that can seamlessly operate across multiple blockchains, limiting innovation and the potential of decentralized ecosystems. +??? interface "Verify VAA" + ```bash + worm verify-vaa INSERT_VAA, INSERT_NETWORK -Wormhole addresses this problem by providing a _generic message-passing_ protocol that enables secure and efficient communication between blockchains. By allowing data and asset transfers across various blockchain networks, Wormhole breaks down the walls that traditionally separate these ecosystems. +Options: + --help Show help [boolean] + --version Show version number [boolean] + -v, --vaa vaa in hex format [string] [required] + -n, --network Network [required] [choices: "mainnet", "testnet", "devnet"] + ``` -Wormhole is distinguished by its focus on robust security, scalability, and transparency. The protocol is supported by a decentralized network of validators that ensure the integrity of every cross-chain transaction. This, combined with Wormhole’s proven performance in real-world applications, gives developers a dependable platform to create and scale multichain applications confidently. +## Examples -![Message-passing process in the Wormhole protocol](/docs/images/protocol/introduction/introduction-1.webp) +### Generate a VAA -!!! note - The above is an oversimplified illustration of the protocol; details about the architecture and components are available on the [architecture page](/docs/protocol/architecture/){target=\_blank}. +Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: -Wormhole allows developers to leverage the strengths of multiple blockchain ecosystems without being confined to one. This means applications can benefit from the unique features of various networks—such as Solana's high throughput, Ethereum's security, and Cosmos's interoperability while maintaining a unified, efficient user experience. +```bash +worm generate registration --module NFTBridge \ + --chain bsc \ + --contract-address 0x706abc4E45D419950511e474C7B9Ed348A4a716c \ + --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 +``` -This page introduces the key concepts and components necessary to understand how Wormhole enables fast, secure, and scalable cross-chain communication. +The below example generates a token attestation VAA: -## What Problems Does Wormhole Solve? +```bash +worm generate attestation --emitter-chain ethereum \ + --emitter-address 11111111111111111111111111111115 \ + --chain ethereum \ + --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ + --decimals 6 \ + --symbol USDC \ + --name USDC \ + --guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0 +``` -Interoperability is a critical challenge in the rapidly evolving blockchain landscape. Individual blockchains are often isolated, limiting the potential for integrated applications operating across multiple ecosystems. Wormhole solves this problem by enabling seamless communication between blockchains, allowing developers to create multichain applications that can leverage the unique features of each network. +### Parse a VAA -Critical problems Wormhole addresses include: +Use `parse` to parse a VAA into JSON: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +```bash +worm parse $(worm-fetch-governance 13940208096455381020) +``` -## What Does Wormhole Offer? +This example will fetch governance VAA `13940208096455381020` and print it as JSON: -Wormhole provides a suite of tools and protocols that support a wide range of use cases: +```bash +# ...signatures elided +timestamp: 1651416474, +nonce: 1570649151, +emitterChain: 1, +emitterAddress: '0000000000000000000000000000000000000000000000000000000000000004', +sequence: 13940208096455381020n, +consistencyLevel: 32, +payload: { + module: 'Core', + type: 'GuardianSetUpgrade', + chain: 0, + newGuardianSetIndex: 2, + newGuardianSetLength: 19, + newGuardianSet: [ + '58cc3ae5c097b213ce3c81979e1b9f9570746aa5', + 'ff6cb952589bde862c25ef4392132fb9d4a42157', + '114de8460193bdf3a2fcf81f86a09765f4762fd1', + '107a0086b32d7a0977926a205131d8731d39cbeb', + '8c82b2fd82faed2711d59af0f2499d16e726f6b2', + '11b39756c042441be6d8650b69b54ebe715e2343', + '54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd', + '66b9590e1c41e0b226937bf9217d1d67fd4e91f5', + '74a3bf913953d695260d88bc1aa25a4eee363ef0', + '000ac0076727b35fbea2dac28fee5ccb0fea768e', + 'af45ced136b9d9e24903464ae889f5c8a723fc14', + 'f93124b7c738843cbb89e864c862c38cddcccf95', + 'd2cc37a4dc036a8d232b48f62cdd4731412f4890', + 'da798f6896a3331f64b48c12d1d57fd9cbe70811', + '71aa1be1d36cafe3867910f99c09e347899c19c3', + '8192b6e7387ccd768277c17dab1b7a5027c0b3cf', + '178e21ad2e77ae06711549cfbb1f9c7a9d8096e8', + '5e1487f35515d02a92753504a8d75471b9f49edb', + '6fbebc898f403e4773e95feb15e80c9a99c8348d' + ] +} +``` -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +### Submit VAAs -## What Isn't Wormhole? +Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +```bash +worm submit $(cat my-nft-registration.txt) --network mainnet +``` -## Use Cases of Wormhole +The script will ask you to specify the target chain for VAAs that don't have a specific target chain (like registrations or Guardian set upgrades). For example, to submit a Guardian set upgrade on all chains, simply run: -Consider the following examples of potential applications enabled by Wormhole: +```bash +worm-fetch-governance 13940208096455381020 > guardian-upgrade.txt +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain oasis +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain aurora +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain fantom +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain karura +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain acala +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain klaytn +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain avalanche +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain polygon +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain bsc +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain solana +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain terra +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain ethereum +worm submit $(cat guardian-upgrade.txt) --network mainnet --chain celo +``` -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. -## Explore +### Fetch Contract Information -Discover more about the Wormhole ecosystem, components, and protocols: +To get info about a contract (only EVM supported at this time), use the following command: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +```bash +worm evm info -c bsc -n mainnet -m TokenBridge +``` -## Demos +Running this command generates the following output: -Demos offer more realistic implementations than tutorials: +```bash +{ + "address": "0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", + "wormhole": "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B", + "implementation": "0x621199f6beB2ba6fbD962E8A52A320EA4F6D4aA3", + "isInitialized": true, + "tokenImplementation": "0x7f8C5e730121657E17E452c5a1bA3fA1eF96f22a", + "chainId": 4, + "finality": 15, + "evmChainId": "56", + "isFork": false, + "governanceChainId": 1, + "governanceContract": "0x0000000000000000000000000000000000000000000000000000000000000004", + "WETH": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + "registrations": { + "Solana": "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5", + "Ethereum": "0x0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585", + "Terra": "0x0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2", + "Polygon": "0x0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde", + "Avalanche": "0x0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052", + "Oasis": "0x0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564", + "Algorand": "0x67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45", + "Aurora": "0x00000000000000000000000051b5123a7b0f9b2ba265f9c4c8de7d78d52f510f", + "Fantom": "0x0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2", + "Karura": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", + "Acala": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624", + "Klaytn": "0x0000000000000000000000005b08ac39eaed75c0439fc750d9fe7e1f9dd0193f", + "Celo": "0x000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed", + "Near": "0x148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7", + "Moonbeam": "0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92", + "Neon": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Terra2": "0xa463ad028fb79679cfc8ce1efba35ac0e77b35080a1abe9bebe83461f176b0a3", + "Injective": "0x00000000000000000000000045dbea4617971d93188eda21530bc6503d153313", + "Osmosis": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Sui": "0xccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5", + "Aptos": "0x0000000000000000000000000000000000000000000000000000000000000001", + "Arbitrum": "0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c", + "Optimism": "0x0000000000000000000000001d68124e65fafc907325e3edbf8c4d84499daa8b", + "Gnosis": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Pythnet": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Xpla": "0x8f9cf727175353b17a5f574270e370776123d90fd74956ae4277962b4fdee24c", + "Btc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Base": "0x0000000000000000000000008d2de8d2f73f1f4cab472ac9a881c9b123c79627", + "Sei": "0x86c5fd957e2db8389553e1728f9c27964b22a8154091ccba54d75f4b10c61f5e", + "Rootstock": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Scroll": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Mantle": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Blast": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d", + "Xlayer": "0x0000000000000000000000005537857664b0f9efe38c9f320f75fef23234d904", + "Linea": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Berachain": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Seievm": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Snaxchain": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Wormchain": "0xaeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924", + "Cosmoshub": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Evmos": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Kujira": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Neutron": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Celestia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Stargaze": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Seda": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Dymension": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Provenance": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "ArbitrumSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "BaseSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "OptimismSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Holesky": "0x0000000000000000000000000000000000000000000000000000000000000000", + "PolygonSepolia": "0x0000000000000000000000000000000000000000000000000000000000000000" + } +} +``` -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +You can get the contract address for a module as follows: - +To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can provide the following command: -!!! note - Wormhole Integration Complete? +```bash +worm info contract mainnet bsc NFTBridge +``` - Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community! +### Fetch Chain Information - **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank}** +You can get the RPC address for a chain as follows: -## Supported Blockchains +```bash +worm info rpc INSERT_NETWORK INSERT_CHAIN +``` -Wormhole supports a growing number of blockchains. +To get the RPC address for BSC Mainnet, for example, you can provide the following command: -text/supported-networks.md +```bash +worm info rpc mainnet bsc +``` --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/protocol/security/ +Doc-Content: https://wormhole.com/docs/tools/dev-env/ --- BEGIN CONTENT --- --- -title: Security -description: Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. -categories: Basics +title: Local Dev Environment +description: Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. +categories: Solidity-SDK, Typescript-SDK --- -# Security +# Development Environment -## Core Security Assumptions +Developers building for smart contract integration will want to set up a development environment to allow testing the full integration, possibly including VAA generation and relaying. -At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. +## Tooling Installation -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) -- The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} -- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator -- Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs -- Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. -In summary: +## Development Stages -- **Core integrators aren't exposed to risk from chains and contracts they don't integrate with** -- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on -- You can expand your contract and chain dependencies as you see fit +Different approaches to development and testing are recommended at various stages of application development. -Core assumptions aside, many other factors impact the real-world security of decentralized platforms. Here is more information on additional measures that have been put in place to ensure the security of Wormhole. +### Initial Development -## Guardian Network +During the initial development of an on-chain application, the best option is to use the native tools available in the environment. You can visit the following resources for more information: -Wormhole is an evolving platform. While the Guardian set currently comprises 19 validators, this is a limitation of current blockchain technology. +- **[Environment](https://github.com/wormhole-foundation/wormhole){target=\_blank}** - select the folder for the desired network to learn about the recommended native toolset +- **[Mock Guardian](https://github.com/wormhole-foundation/wormhole/blob/main/sdk/js/src/mock/wormhole.ts){target=\_blank}** - it's recommended to set up a mock Guardian or Emitter to provide signed VAAsFor any program methods that require some message be sent or received. +- **[Wormhole Scaffolding repository](https://github.com/wormhole-foundation/wormhole-scaffolding/blob/main/evm/ts-test/01_hello_world.ts){target=\_blank}** - example mock Guardian test -### Governance +Relying on native tools when possible allows for more rapid prototyping and iteration. -Governance is the process through which contract upgrades happen. Guardians manually vote on governance proposals that originate inside the Guardian Network and are then submitted to ecosystem contracts. +### Integration -This means that governance actions are held to the same security standard as the rest of the system. A two-thirds supermajority of the Guardians is required to pass any governance action. +For integration to Wormhole and with multiple chains, the simplest option is to use the chains' Testnets. In choosing which chains to use for integration testing, consider which chains in a given environment provide easy access to Testnet tokens and where block times are fast. Find links for Testnet faucets in the [blockchain details section](/docs/products/reference/supported-networks/){target=\_blank}. A developer may prefer standing up a set of local validators instead of using the Testnet. For this option, [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} is available to run local instances of all the chains Wormhole supports. -Governance messages can target any of the various wormhole modules, including the core contracts and all currently deployed token bridge contracts. When a Guardian signs such a message, its signature implies a vote on the action in question. Once more than two-thirds of the Guardians have signed, the message and governance action are considered valid. +!!! note + Variation in host environments causes unique issues, and the computational intensity of multiple simultaneous local validators can make setting them up difficult or time-consuming. You may prefer Testnets for the simplest integration testing. -All governance actions and contract upgrades have been managed via Wormhole's on-chain governance system. +### Prepare for Deployment -Via governance, the Guardians can: +Once you've finished the application's initial development and performed integration testing, you should set up a CI test environment. The best option for that is likely to be [Tilt](https://tilt.dev/){target=\_blank} since it allows you to spin up any chains supported by Wormhole in a consistent environment. -- Change the current Guardian set -- Expand the Guardian set -- Upgrade ecosystem contract implementations +## Validator Setup with Tilt -The governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\_blank} for contract source. +### Tilt +If you'd like to set up a local validator environment, follow the setup guide for Tilt. Tilt is a full-fledged Kubernetes deployment of every chain connected to Wormhole, along with a Guardian node. It usually takes 30 minutes to spin up fully, but it comes with all chains running out of the box. Refer to the [Tilt](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} page for a complete guide to setting up and configuring Tilt. -## Monitoring +## Deploying to Public Networks -A key element of Wormhole's defense-in-depth strategy is that each Guardian is a highly competent validator company with its own in-house processes for running, monitoring, and securing blockchain operations. This heterogeneous approach to monitoring increases the likelihood that fraudulent activity is detected and reduces the number of single failure points in the system. +### Testnet -Guardians are not just running Wormhole validators; they're running validators for every blockchain inside of Wormhole as well, which allows them to perform monitoring holistically across decentralized computing rather than just at a few single points. +When doing integration testing on Testnets, remember that a single Guardian node is watching for transactions on various test networks. Because Testnets only have a single Guardian, there's a slight chance that your VAAs won't be processed. This rate doesn't indicate performance on Mainnet, where 19 Guardians are watching for transactions. The Testnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Testnet endpoint: -Guardians monitor: +```text +https://api.testnet.wormholescan.io +``` -- Block production and consensus of each blockchain - if a blockchain's consensus is violated, it will be disconnected from the network until the Guardians resolve the issue -- Smart contract level data - via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains -- Guardian level activity - the Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators +### Mainnet -## Asset Layer Protections +The Mainnet contract addresses are available on the page for each [environment](/docs/products/reference/supported-networks/){target=\_blank}. The [Wormholescan API](https://docs.wormholescan.io){target=\_blank} offers the following Guardian equivalent Mainnet endpoint: -One key strength of the Wormhole ecosystem is the Guardians’ ability to validate and protect the integrity of assets across multiple blockchains. +```text +https://api.wormholescan.io +``` +--- END CONTENT --- -To enforce the Wormhole Asset Layer’s core protections, the Global Accountant tracks the total circulating supply of all Wormhole assets across all chains, preventing any blockchain from bridging assets that could violate the supply invariant. +Doc-Content: https://wormhole.com/docs/tools/faqs/ +--- BEGIN CONTENT --- +--- +title: Toolkit FAQs +description: FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. +categories: Solidity-SDK, Typescript-SDK +--- -In addition to the Global Accountant, Guardians may only sign transfers that do not violate the requirements of the Governor. The [Governor](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0007_governor.md){target=\_blank} tracks inflows and outflows of all blockchains and delays suspicious transfers that may indicate an exploit. +# Toolkit FAQs -## Open Source +## Why does the `toNative` function in the TypeScript SDK return an error? -Wormhole builds in the open and is always open source. +The `toNative` function may return an error if the platform-specific module (such as Solana or EVM) is not correctly imported or passed into the Wormhole constructor. -- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\_blank}** -- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\_blank}** -- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** +To fix this, ensure the relevant platform module is imported and included when initializing Wormhole. For example, if you're working with Solana, make sure to import the Solana module and pass it into the Wormhole constructor like this: -## Audits +```typescript +import solana from '@wormhole-foundation/sdk/solana'; +const wh = await wormhole('Testnet', [solana]); +``` -Wormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms: +## How can I retrieve the history of previously bridged transactions? -- [Trail of Bits](https://www.trailofbits.com/){target=\_blank} -- [Neodyme](https://neodyme.io/en/){target=\_blank} -- [Kudelski](https://kudelskisecurity.com/){target=\_blank} -- [OtterSec](https://osec.io/){target=\_blank} -- [Certik](https://www.certik.com/){target=\_blank} -- [Hacken](https://hacken.io/){target=\_blank} -- [Zellic](https://www.zellic.io/){target=\_blank} -- [Coinspect](https://www.coinspect.com/){target=\_blank} -- [Halborn](https://www.halborn.com/){target=\_blank} -- [Cantina](https://cantina.xyz/welcome){target=\_blank} +To retrieve the history of previously bridged transactions, you can use the Wormholescan API. Use the following endpoint to query the transaction history for a specific address: -All audits and final reports can be found in [security page of the GitHub Repo](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#3rd-party-security-audits){target=\blank}. +```bash +https://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS +``` -## Bug Bounties +Simply replace `INSERT_ADDRESS_HERE` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions. -Wormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community. +???- example "Fetch transaction history for a specific address" + ```bash + curl -X GET "https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38" -H "accept: application/json" + ``` -Wormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\blank} program, with a top payout of **5 million dollars**. +## How can I manually submit a VAA to a destination chain in the correct format? -If you are interested in contributing to Wormhole security, please look at this section for [Getting Started as a White Hat](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md#white-hat-hacking){target=\blank}, and follow the [Wormhole Contributor Guidelines](https://github.com/wormhole-foundation/wormhole/blob/main/CONTRIBUTING.md){target=\blank}. +To manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps: -For more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\blank}. +1. **Obtain the VAA in Base64 format** - navigate to the **Advanced** tab in [Wormholescan](https://wormholescan.io/){target=\_blank} to find the VAA associated with the transaction you want to submit and copy the VAA in base64 format -## Learn More + ```bash + https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced + ``` -The [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\blank} from the official repository has the latest security policies and updates. +2. **Convert the VAA to hex** - you must convert the base64 VAA into a hexadecimal (hex) format before submitting it to the destination chain. This can be done using various online tools or via command-line utilities like `xxd` or a script in a language like Python + +3. **Submit the VAA through Etherscan (for EVM chains)** - once the VAA is in hex format, go to the [Etherscan UI](https://etherscan.io/){target=\_blank} and submit it through the [`TokenBridge`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\_blank} contract’s method (such as the `CompleteTransfer` function or `CompleteTransferWithPayload`) + + - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\_blank} section + + - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field + +Following these steps, you can manually submit a VAA in the proper format to a destination chain. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/solidity-sdk/get-started/ @@ -22119,42 +20567,32 @@ categories: Solidity-SDK # Solidity SDK -## Introduction - -The [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} simplifies cross-chain messaging on EVM-compatible chains by providing essential Solidity interfaces, utility libraries, and testing tools. It allows developers to build secure and efficient cross-chain decentralized applications (dApps) without manually interacting with Wormhole’s core contracts across multiple chains. +This page covers all you need to know about the functionality offered through the Wormhole Solidity SDK. -By abstracting away complex interactions, the SDK drastically reduces the overhead associated with cross-chain development. It provides: +
    - - **Unified interfaces** - developers can use a standardized set of Solidity interfaces to handle cross-chain messaging, token transfers, and verifiable action approvals (VAAs) without needing to manage the underlying infrastructure - - **Automated message delivery** - the SDK leverages Wormhole’s relayer infrastructure, automatically delivering messages across chains, reducing the need for manual intervention, and simplifying gas management on the target chain - - **Seamless integration with Wormhole services** - the SDK integrates with Wormhole’s `TokenBridge` and Circle’s CCTP, providing built-in mechanisms for cross-chain asset transfers, making token bridges and cross-chain messaging easy to implement - - **Testing and development tools** - it comes with comprehensive tools for local testing and simulation, allowing developers to validate their cross-chain logic before deployment, minimizing the risk of errors in production environments +- :octicons-download-16:{ .lg .middle } **Installation** -These features significantly streamline the development workflow by reducing complexity and offering tools compatible with various EVM versions. This helps developers avoid issues that arise from differences in EVM equivalence across chains. + --- -This guide covers installation, key concepts, and usage examples to help you build secure cross-chain applications using the SDK, from token transfers to advanced message passing. + Find installation instructions using Foundry and Forge to pull the necessary libraries into your project. -## Installation + [:custom-arrow: Install the SDK](/docs/tools/solidity-sdk/get-started/#installation) -To install the SDK, use [Foundry and Forge](https://book.getfoundry.sh/getting-started/installation){target=\_blank}. This pulls the necessary libraries into your project: +- :octicons-download-16:{ .lg .middle } **Source Code** -```bash -forge install wormhole-foundation/wormhole-solidity-sdk@v0.1.0 -``` + --- -When developing cross-chain applications, ensure that the chains you target support the EVM version you’re using. For instance, the PUSH0 opcode (introduced in Solidity 0.8.20) may not be available on all chains. To avoid compatibility issues, you can set the EVM version in your `foundry.toml` file: + Want to go straight to the source? Check out the Solidity SDK GitHub repository. -```toml -evm_version = "paris" -``` + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} -This ensures compatibility across all targeted chains, even if some do not yet support the latest EVM upgrades. +
    ## Key Considerations Before deploying applications using the Wormhole Solidity SDK, keep these considerations in mind: - - **Version compatibility** - the SDK is evolving, and using tagged releases for production is crucial, as the main branch may introduce breaking changes - **IERC-20 remapping** - the SDK provides a remapping mechanism to handle potential conflicts between different implementations of IERC20, ensuring seamless integration with other libraries - **Testing** - given the cross-chain dependencies, testing all integrations is critical to avoid issues in production environments @@ -22184,7 +20622,18 @@ Please refer to the complete `WormholeRelayerSDK.sol` file below for further det ???- code "`WormholeRelayerSDK.sol`" ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-1.sol + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/constants/Chains.sol"; +import "wormhole-sdk/Utils.sol"; + +import {Base} from "wormhole-sdk/WormholeRelayer/Base.sol"; +import {TokenBase, TokenReceiver, TokenSender} from "wormhole-sdk/WormholeRelayer/TokenBase.sol"; +import {CCTPBase, CCTPReceiver, CCTPSender} from "wormhole-sdk/WormholeRelayer/CCTPBase.sol"; +import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "wormhole-sdk/WormholeRelayer/CCTPAndTokenBase.sol"; ``` ### Base Contract Overview @@ -22194,20 +20643,87 @@ The [`Base.sol`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/bl - **`onlyWormholeRelayer()`** - a modifier that ensures only authorized messages from the Wormhole relayer contract are processed, restricting access to certain functions ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:22:28 + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } ``` - **`setRegisteredSender()`** - restricts message acceptance to a registered sender from a specific chain, ensuring messages are only processed from trusted sources ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol:45:54 + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } ``` These security measures ensure messages come from the correct source and are processed securely. Please refer to the complete `Base.sol` contract below for further details. ???- code "`Base.sol`" ```solidity - code/tools/solidity-sdk/sdk-reference/solidity-sdk-2.sol + // SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.19; + +import "wormhole-sdk/interfaces/IWormholeReceiver.sol"; +import "wormhole-sdk/interfaces/IWormholeRelayer.sol"; +import "wormhole-sdk/interfaces/IWormhole.sol"; +import "wormhole-sdk/Utils.sol"; + +abstract contract Base { + IWormholeRelayer public immutable wormholeRelayer; + IWormhole public immutable wormhole; + + address registrationOwner; + mapping(uint16 => bytes32) registeredSenders; + + constructor(address _wormholeRelayer, address _wormhole) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + wormhole = IWormhole(_wormhole); + registrationOwner = msg.sender; + } + + modifier onlyWormholeRelayer() { + require( + msg.sender == address(wormholeRelayer), + "Msg.sender is not Wormhole Relayer" + ); + _; + } + + modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) { + require( + registeredSenders[sourceChain] == sourceAddress, + "Not registered sender" + ); + _; + } + + /** + * Sets the registered address for 'sourceChain' to 'sourceAddress' + * So that for messages from 'sourceChain', only ones from 'sourceAddress' are valid + * + * Assumes only one sender per chain is valid + * Sender is the address that called 'send' on the Wormhole Relayer contract on the source chain) + */ + function setRegisteredSender( + uint16 sourceChain, + bytes32 sourceAddress + ) public { + require( + msg.sender == registrationOwner, + "Not allowed to set registered sender" + ); + registeredSenders[sourceChain] = sourceAddress; + } +} ``` ### Interface for Cross-Chain Messages @@ -22242,7 +20758,32 @@ This section covers cross-chain messaging and token transfers and shows how to u To send a cross-chain message, inherit from the base contract provided by the SDK and use its helper methods to define your message and sender address. Here’s a basic example: ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-3.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/Base.sol"; + +contract CrossChainSender is Base { + constructor( + address _wormholeRelayer, + address _wormhole + ) Base(_wormholeRelayer, _wormhole) {} + + function sendMessage( + bytes memory message, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Register sender and send message through WormholeRelayer + setRegisteredSender(targetChain, msg.sender); + onlyWormholeRelayer().sendPayloadToEvm( + targetChain, + address(targetAddress), + message, + 0, + 500_000 + ); + } +} ``` This contract extends `Base.sol` and allows sending cross-chain messages securely using the `WormholeRelayer`. @@ -22252,7 +20793,26 @@ This contract extends `Base.sol` and allows sending cross-chain messages securel The SDK enables seamless token transfers between EVM-compatible chains in addition to sending messages. To facilitate cross-chain token transfers, you can extend the SDK's `TokenSender` and `TokenReceiver` base contracts. ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-4.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenSender is TokenSender { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenSender(_wormholeRelayer, _wormhole) {} + + function sendToken( + address token, + uint256 amount, + uint16 targetChain, + bytes32 targetAddress + ) external payable { + // Send tokens across chains + transferTokenToTarget(token, amount, targetChain, targetAddress); + } +} ``` In this example, `TokenSender` initiates a token transfer to another chain. The SDK’s built-in utilities securely handle token transfers, ensuring proper VAAs are generated and processed. @@ -22262,7 +20822,28 @@ In this example, `TokenSender` initiates a token transfer to another chain. The To receive tokens on the target chain, implement a contract that inherits from `TokenReceiver` and overrides the `receiveWormholeMessages` function. ```solidity -code/tools/solidity-sdk/sdk-reference/solidity-sdk-5.sol +pragma solidity ^0.8.19; + +import "@wormhole-foundation/wormhole-solidity-sdk/src/WormholeRelayer/TokenBase.sol"; + +contract CrossChainTokenReceiver is TokenReceiver { + constructor( + address _wormholeRelayer, + address _wormhole + ) TokenReceiver(_wormholeRelayer, _wormhole) {} + + // Function to handle received tokens from another chain + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalMessages, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable override { + // Process the received tokens here + receiveTokens(payload); + } +} ``` In this example, `TokenReceiver` allows the contract to handle tokens sent from the source chain. Once the cross-chain message is received, the `receiveWormholeMessages` function processes the incoming tokens. Always validate the message's authenticity and source. diff --git a/llms.txt b/llms.txt index 0b8bd3dc9..7860374c1 100644 --- a/llms.txt +++ b/llms.txt @@ -4,34 +4,10 @@ ## Docs -- [Core Messaging Layer Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/core-messaging/index.md): Learn to use Wormhole’s foundational messaging contracts to build multichain apps with direct control over publishing, verifying, relaying, and more. -- [Getting Started with MultiGov](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/multigov/index.md): Learn how to get started with MultiGov, from evaluating cross-chain governance needs to deploying with help from the Tally team. -- [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/overview.md): Explore Wormhole Queries, offering real-time access to verified blockchain data via a REST endpoint, enabling secure cross-chain interactions and verifications. -- [Use Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/queries/use-queries.md): Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. -- [Use Cases](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/start-building/use-cases.md): Explore Wormhole's use cases, from cross-chain swaps to DeFi, lending, gaming, and more. See how projects integrate Wormhole solutions. -- [Wormhole CLI](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/cli.md): Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. -- [Local Dev Environment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/dev-env.md): Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. -- [Toolkit FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/toolkit/faqs.md): FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. -- [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/cctp.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. -- [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/index.md): Wormhole Connect is a React widget offering an easy-to-use interface to facilitate multichain asset transfers via Wormhole directly in a web application. -- [Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/connect/overview.md): Explore Wormhole Connect, the React widget that allows you to offer an easy-to-use UI for cross-chain asset transfers via Wormhole in a web application. -- [Native Token Transfers Installation](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/installation.md): Learn how to Install Wormhole’s Native Token Transfers (NTT) framework, a flexible and composable framework for transferring tokens across blockchains. -- [Native Token Transfers Post Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/deployment-process/post-deployment.md): Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. -- [Native Token Transfers (NTT)](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/index.md): This section provides comprehensive guidance on configuring, deploying, and managing your Native Token Transfers (NTT) integration. -- [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/native-token-transfers/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. -- [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..build/transfers/token-bridge.md): Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. -- [Glossary](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/glossary.md): Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. -- [MultiGov Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/governance/overview.md): Explore MultiGov, a cross-chain governance system using Wormhole for seamless voting and proposal execution across multiple blockchain networks. -- [Circle's CCTP Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/cctp.md): Unlock fast USDC transfers with Wormhole's integration of Circle's CCTP, featuring automatic relaying via the Wormhole relayer and native gas solutions. -- [Multichain Transfers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/index.md): This section introduces the core messaging protocols that power seamless multichain communication and asset transfer within the Wormhole ecosystem. -- [Native Token Transfers - Deployment Models](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/deployment.md): Explore Wormhole's Native Token Transfers deployment models——hub-and-spoke, burn-and-mint——for seamless cross-chain token transfers. -- [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/native-token-transfers/overview.md): Explore Wormhole's Native Token Transfers for flexible cross-chain transfers with full control over token behavior, security, and integration features. -- [Wormhole Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/settlement/overview.md): Discover Wormhole Settlement, enabling fast, intent-based asset transfers across Ethereum, Solana, Sui, and more for institutions and builders. -- [Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/..learn/transfers/token-bridge.md): Learn about Wormhole's Token Bridge for cross-chain transfers using lock and mint mechanisms, ensuring secure and efficient asset movement. - [AI Resources](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md): Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md): No description available. - [Get Started with CCTP](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/transfer-usdc.md): No description available. +- [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/cctp-contracts.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. - [CCTP Bridge with Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md): Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. - [Complete USDC Transfer Flow](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/tutorials/complete-usdc-transfer.md): Learn how to perform USDC cross-chain transfers using Wormhole SDK and Circle's CCTP. Supports manual, automatic, and partial transfer recovery. - [Routes](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/concepts/routes.md): Explore Wormhole Connect's routing capabilities for asset transfers, featuring Token Bridge, CCTP, NTT, and various blockchain-specific routes for optimal UX. @@ -40,6 +16,7 @@ - [Connect Theme & UI Customization](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/configuration/theme.md): Learn how to style Wormhole Connect with custom color schemes, fonts, layouts, and menus for a streamlined user experience. - [Connect FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/faqs.md): Common questions and detailed answers about using Wormhole Connect, including supported assets, chains, customization, and integration options. - [Get Started with Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/get-started.md): Follow this guide to configure and use the Connect UI widget to easily add an intuitive, multichain asset transfer UI to your web applications. +- [Integrate Connect via CDN](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/hosted-version.md): None - [Wormhole Connect v1.0 Migration Guide](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/guides/upgrade.md): Learn how to migrate to Wormhole Connect v1.0, with step-by-step guidance on updating your package and configuration. - [Wormhole Connect](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/overview.md): With Wormhole Connect, you can seamlessly bridge digital assets and data across a wide range of supported blockchain networks. - [Features](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/connect/reference/support-matrix.md): Explore a comprehensive Feature Support matrix and explain Wormhole's capabilities across networks for Token Bridge, CCTP, ETH Bridge, and more. @@ -69,9 +46,11 @@ - [Native Token Transfers EVM Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-evm.md): Deploy and configure Wormhole’s Native Token Transfers (NTT) for EVM chains, including setup, token compatibility, mint/burn modes, and CLI usage. - [Native Token Transfers Solana Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/deploy-to-solana.md): Deploy and configure Wormhole's Native Token Transfers (NTT) for Solana, including setup, token compatibility, mint/burn modes, and CLI usage. - [Deploy Native Token Transfers with Launchpad](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/evm-launchpad.md): Deploy a new token or extend an existing one across multiple chains with the NTT Launchpad. Manage transfers, supply, and settings—all from a single platform. +- [Native Token Transfers Post Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/post-deployment.md): Learn post-deployment guidelines for optimizing Wormhole NTT, which include testing, security, frontend integration, ecosystem coordination, and monitoring. +- [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/guides/troubleshoot.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. - [Native Token Transfers Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/overview.md): With Native Token Transfers, you can directly transfer a blockchain's native assets across various connected networks. - [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. -- [Troubleshooting NTT Deployment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/troubleshooting.md): Resolve common issues in NTT deployment with this troubleshooting guide covering Solana, EVM, mint authority, decimals, and rate limits. +- [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. - [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. - [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md): No description available. - [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. @@ -87,6 +66,7 @@ - [Chain IDs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/chain-ids.md): This page documents the Wormhole-specific chain IDs for each chain and contrasts them to the more commonly referenced EVM chain IDs originating in EIP-155. - [Wormhole Finality | Consistency Levels](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/consistency-levels.md): This page documents how long to wait for finality before signing, based on each chain’s consistency (finality) level and consensus mechanism. - [Contract Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/contract-addresses.md): This page documents the deployed contract addresses of the Wormhole contracts on each chain, including Core Contracts, TokenBridge, and more. +- [Glossary](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/glossary.md): Explore a comprehensive glossary of technical terms and key concepts used in the Wormhole network, covering Chain ID, Guardian, VAA, and more. - [Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/supported-networks.md): Learn about the networks each Wormhole product supports, and explore links to documentation, official websites, and block explorers. - [Testnet Faucets](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/testnet-faucets.md): This page includes resources to quickly find the Testnet tokens you need to deploy and test applications and contracts on Wormhole's supported networks. - [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. @@ -101,7 +81,7 @@ - [Flow of a Token Bridge Transfer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md): Learn how the Wormhole Token Bridge enables secure, cross-chain token transfers by combining token-specific logic with Wormhole's core message-passing layer. - [Token Bridge FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md): Find answers to common questions about the Wormhole Token Bridge, including managing wrapped assets and understanding gas fees. - [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/get-started.md): Perform token transfers using Wormhole’s Token Bridge with the TypeScript SDK, including manual (Solana–Sepolia) and automatic (Fuji–Alfajores). -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/transfer-wrapped-assets.md): No description available. +- [Get Started with Token Bridge](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/guides/token-bridge-contracts.md): Learn how to integrate Wormhole's Token Bridge for seamless multichain token transfers with a lock-and-mint mechanism and cross-chain asset management. - [Token Bridge Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/overview.md): With Wormhole Token Bridge, you can enable secure, multichain communication, build multichain apps, sync data, and coordinate actions across blockchains. - [Create Multichain Tokens](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/multichain-token.md): Learn how to create a multichain token, bridge tokens across blockchains, and update metadata for seamless multichain interoperability. - [Transfer Tokens via Token Bridge Tutorial](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/tutorials/transfer-workflow.md): Learn to build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains @@ -115,6 +95,9 @@ - [VAAs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/infrastructure/vaas.md): Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and role in cross-chain communication. - [Introduction to Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/introduction.md): Wormhole is a protocol for seamless communication between blockchains, enabling cross-chain applications and integrations. - [Security](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/protocol/security.md): Explore Wormhole's security features, including the Guardian network, governance, monitoring, open-source development, and bug bounty programs. +- [Wormhole CLI](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/cli/get-started.md): Learn how to install and use the Wormhole CLI, including commands and examples for managing multichain deployments, generating VAAs, and querying contract info. +- [Local Dev Environment](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/dev-env.md): Learn how to configure a development environment to build with Wormhole, including using the CLI, local validators, testing on public test networks, and more. +- [Toolkit FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/faqs.md): FAQs on Wormhole Toolkit, covering Wormholescan, CLI, SDKs (TypeScript, Solidity), Tilt, error handling, transaction history, and manual VAA submission. - [Get Started with the Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/get-started.md): Follow this guide to use the Wormhole Solidity SDK's interfaces and tools to help you quickly build on-chain integrations using smart contracts. - [Solidity SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/solidity-sdk/sdk-reference.md): How to use the Wormhole Solidity SDK for cross-chain messaging, token transfers, and integrating decentralized applications on EVM-compatible blockchains. - [Get Started with the TypeScript SDK](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/tools/typescript-sdk/get-started.md): Follow this guide to install the Wormhole TypeScript SDK, initialize a Wormhole instance, and add the platforms your integration supports. diff --git a/products/cctp-bridge/guides/.pages b/products/cctp-bridge/guides/.pages index 1930ddb9f..a74182f73 100644 --- a/products/cctp-bridge/guides/.pages +++ b/products/cctp-bridge/guides/.pages @@ -1,3 +1,3 @@ title: Guides nav: -- 'Transfer USDC': transfer-usdc.md +- 'Interact with Contracts': cctp-contracts.md diff --git a/..build/transfers/cctp.md b/products/cctp-bridge/guides/cctp-contracts.md similarity index 94% rename from ..build/transfers/cctp.md rename to products/cctp-bridge/guides/cctp-contracts.md index 3acdb9576..1fc825f70 100644 --- a/..build/transfers/cctp.md +++ b/products/cctp-bridge/guides/cctp-contracts.md @@ -4,11 +4,11 @@ description: Learn how to interact directly with Circle's CCTP Bridge contracts, categories: Transfer --- -# Get Started with CCTP +# Interact with CCTP Contracts ## Introduction -Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/learn/transfers/cctp/){target=\_blank} by Circle is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. +Circle's [Cross-Chain Transfer Protocol (CCTP)](/docs/products/cctp-bridge/overview/){target=\_blank} is a permissionless utility that facilitates secure and efficient USDC transfers across blockchain networks through native burning and minting mechanisms. As decentralized finance (DeFi) protocols evolve, the need for flexible, secure cross-chain messaging has expanded, requiring solutions beyond simple asset transfers. Wormhole enhances CCTP's capabilities by allowing developers to compose more complex cross-chain interactions. With Wormhole's generic messaging, applications can execute smart contract logic alongside native USDC transfers, enabling richer, more versatile cross-chain experiences. @@ -34,7 +34,7 @@ This contract can be found in [Wormhole's `wormhole-circle-integration` reposito ??? code "Circle Integration contract" ```solidity - --8<-- 'code/build/transfers/cctp/CircleIntegration.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/CircleIntegration.sol' ``` The functions provided by the Circle Integration contract are as follows: @@ -216,7 +216,7 @@ Additionally, the contract provides methods for updating or replacing previously ??? code "Token Messenger contract" ```solidity - --8<-- 'code/build/transfers/cctp/TokenMessenger.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/TokenMessenger.sol' ``` This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol){target=\_blank} on GitHub. @@ -259,7 +259,7 @@ The functions provided by the Token Messenger contract are as follows: `DepositForBurn` - event emitted when `depositForBurn` is called. The `destinationCaller` is set to `bytes32(0)` to allow any address to call `receiveMessage` on the destination domain - --8<-- 'text/build/transfers/cctp/DepositForBurn-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/DepositForBurn-event.md' - **`depositForBurnWithCaller`** - deposits and burns tokens from the sender to be minted on the destination domain. This method differs from `depositForBurn` in that the mint on the destination domain can only be called by the designated `destinationCaller` address @@ -303,7 +303,7 @@ The functions provided by the Token Messenger contract are as follows: `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called - --8<-- 'text/build/transfers/cctp/DepositForBurn-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/DepositForBurn-event.md' - **`replaceDepositForBurn`** — replaces a previous `BurnMessage` to modify the mint recipient and/or the destination caller. The replacement message reuses the `_nonce` created by the original message, which allows the original message's sender to update the details without requiring a new deposit @@ -339,7 +339,7 @@ The functions provided by the Token Messenger contract are as follows: `DepositForBurn` - event emitted when `replaceDepositForBurn` is called. Note that the `destinationCaller` will reflect the new destination caller, which may be the same as the original destination caller, a new destination caller, or an empty destination caller (`bytes32(0)`), indicating that any destination caller is valid - --8<-- 'text/build/transfers/cctp/DepositForBurn-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/DepositForBurn-event.md' - **`handleReceiveMessage`** - handles an incoming message received by the local `MessageTransmitter` and takes the appropriate action. For a burn message, it mints the associated token to the requested recipient on the local domain. @@ -415,7 +415,7 @@ Additional features include replacing previously sent messages, setting maximum ??? code "Message Transmitter contract" ```solidity - --8<-- 'code/build/transfers/cctp/MessageTransmitter.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/MessageTransmitter.sol' ``` This contract and the interfaces, contracts, and libraries it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol){target=\_blank} on GitHub. @@ -504,7 +504,7 @@ The functions provided by the Message Transmitter contract are as follows: ??? interface "Emits" - --8<-- 'text/build/transfers/cctp/MessageSent-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/MessageSent-event.md' - **`sendMessageWithCaller`** — sends a message to the destination domain and recipient, requiring a specific caller to trigger the message on the target chain. It increments the `nonce`, assigns a unique `nonce` to the message, and emits a `MessageSent` event @@ -540,7 +540,7 @@ The functions provided by the Message Transmitter contract are as follows: ??? interface "Emits" - --8<-- 'text/build/transfers/cctp/MessageSent-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/MessageSent-event.md' - **`replaceMessage`** — replaces an original message with a new message body and/or updates the destination caller. The replacement message reuses the `_nonce` created by the original message @@ -574,7 +574,7 @@ The functions provided by the Message Transmitter contract are as follows: ??? interface "Emits" - --8<-- 'text/build/transfers/cctp/MessageSent-event.md' + --8<-- 'text/products/cctp-bridge/guides/cctp-contracts/MessageSent-event.md' ### Token Minter Contract @@ -586,7 +586,7 @@ To enhance control and flexibility, the contract includes mechanisms to pause op ??? code "Token Minter contract" ```solidity - --8<-- 'code/build/transfers/cctp/TokenMinter.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/TokenMinter.sol' ``` This contract and the interfaces and contracts it relies on are stored in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMinter.sol){target=\_blank} on GitHub. @@ -629,13 +629,13 @@ To streamline this process, you can use the [Wormhole Solidity SDK](https://gith ??? code "CCTP Sender contract" ```solidity - --8<-- 'code/build/transfers/cctp/CCTPSender.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/CCTPSender.sol' ``` The `CCTPSender` abstract contract exposes the `sendUSDCWithPayloadToEvm` function. This function publishes a CCTP transfer of the provided `amount` of USDC and requests that the transfer be delivered along with a `payload` to the specified `targetAddress` on the `targetChain`. ```solidity ---8<-- 'code/build/transfers/cctp/sendUSDCWithPayloadToEvm.sol' +--8<-- 'code/products/cctp-bridge/guides/cctp-contracts/sendUSDCWithPayloadToEvm.sol' ``` ??? interface "Parameters" @@ -696,7 +696,7 @@ When the `sendUSDCWithPayloadToEvm` function is called, the following series of A simple example implementation is as follows: ```solidity ---8<-- 'code/build/transfers/cctp/sendCrossChainDeposit.sol' +--8<-- 'code/products/cctp-bridge/guides/cctp-contracts/sendCrossChainDeposit.sol' ``` The above example sends a specified amount of USDC and the recipient's address as a payload to a target contract on another chain, ensuring that the correct cost is provided for the cross-chain transfer. @@ -710,7 +710,7 @@ Using the Wormhole-deployed relayer automatically triggers the `receiveWormholeM ??? code "CCTP Receiver contract" ```solidity - --8<-- 'code/build/transfers/cctp/CCTPReceiver.sol' + --8<-- 'code/products/cctp-bridge/guides/cctp-contracts/CCTPReceiver.sol' ``` Although you do not need to interact with the `receiveWormholeMessages` function directly, it's important to understand what it does. This function processes cross-chain messages and USDC transfers via Wormhole's Circle (CCTP) Bridge. Here's a summary of what it does: @@ -727,7 +727,7 @@ Although you do not need to interact with the `receiveWormholeMessages` functi You'll need to implement the `receivePayloadAndUSDC` function to transfer the USDC and handle the payload as your application needs. A simple example implementation is as follows: ```solidity ---8<-- 'code/build/transfers/cctp/receivePayloadAndUSDC.sol' +--8<-- 'code/products/cctp-bridge/guides/cctp-contracts/receivePayloadAndUSDC.sol' ``` ## Complete Example diff --git a/products/cctp-bridge/guides/transfer-usdc.md b/products/cctp-bridge/guides/transfer-usdc.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/cctp-bridge/guides/transfer-usdc.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/connect/get-started.md b/products/connect/get-started.md index 9d1386f7c..343bb527e 100644 --- a/products/connect/get-started.md +++ b/products/connect/get-started.md @@ -12,6 +12,14 @@ categories: Connect, Transfer Connect helps you to easily add an intuitive, multichain asset transfer UI to your web applications. The guide demonstrates how to configure the Connect widget, add it to a React application, and view it locally. +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + ## Prerequisites Before you begin, make sure you have the following: @@ -23,7 +31,7 @@ Before you begin, make sure you have the following: - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\_blank} - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required) -## Install and Setup Project +## Install and Set Up Project 1. Clone the demo repository and navigate to the project directory: @@ -69,8 +77,9 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -For more `config` options, see the [Connect Data Configuration](/docs/products/connect/configuration/data/){target=\_blank} guide. +Use the following guides to configure your Connect instance: -For more `theme` options, see the [Connect Theme Configuration](/docs/products/connect/configuration/theme/){target=\_blank} guide. +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. diff --git a/products/connect/guides/.pages b/products/connect/guides/.pages index 4c071d7b7..b94115f68 100644 --- a/products/connect/guides/.pages +++ b/products/connect/guides/.pages @@ -1,3 +1,4 @@ title: Guides nav: +- 'Integrate via CDN': hosted-version.md - 'Migration to v1': upgrade.md \ No newline at end of file diff --git a/products/connect/guides/hosted-version.md b/products/connect/guides/hosted-version.md new file mode 100644 index 000000000..6ddbeff57 --- /dev/null +++ b/products/connect/guides/hosted-version.md @@ -0,0 +1,42 @@ +--- +title: Integrate Connect via CDN +description: +categories: Connect, Transfer +--- + +# Integrate Connect via CDN + +[Wormhole Connect](/docs/products/connect/overview/){target=\_blank} is a prebuilt UI component that makes it easy to transfer tokens across chains. You can integrate it into any website using either React or a hosted version served via [jsDelivr](https://www.jsdelivr.com/){target=\_blank}. + +This guide focuses on using the hosted version—ideal for simpler setups or non-React environments. It includes everything you need to get started with just a few lines of code. + +If you're using React, refer to the [Get Started with Connect](/docs/products/connect/get-started/){target=\_blank} guide. + +## Install Connect + +To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: + +```bash +npm i @wormhole-foundation/wormhole-connect +``` + +## Add Connect to Your Project Using the Hosted Version + +The hosted version uses pre-built packages (including React) served via jsDelivr from npm. To integrate it without using React directly, add the following to your JavaScript project: + +```js +--8<-- 'code/products/connect/guides/hosted-version/hosted-1.js' +``` + +You can provide config and theme parameters in a second function argument: + +```js +--8<-- 'code/products/connect/guides/hosted-version/hosted-2.js' +``` + +## Next Steps + +Use the following guides to configure your Connect instance: + +- **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. +- **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. diff --git a/products/connect/overview.md b/products/connect/overview.md index 50dc3c787..654db14c6 100644 --- a/products/connect/overview.md +++ b/products/connect/overview.md @@ -59,4 +59,4 @@ Here are some key use cases that highlight the power and versatility of Connect: Add Connect to your app with these key setup steps: -[timeline(wormhole-docs/.snippets/text/products/reference/connect/overview/connect-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/connect/overview/connect-timeline.json)] diff --git a/products/native-token-transfers/.pages b/products/native-token-transfers/.pages index 0a3b59977..2981eb884 100644 --- a/products/native-token-transfers/.pages +++ b/products/native-token-transfers/.pages @@ -5,6 +5,5 @@ nav: - guides - configuration - concepts -- 'Troubleshooting': troubleshooting.md - 'FAQs': faqs.md - reference diff --git a/products/native-token-transfers/faqs.md b/products/native-token-transfers/faqs.md index 89a7048e3..c976ab682 100644 --- a/products/native-token-transfers/faqs.md +++ b/products/native-token-transfers/faqs.md @@ -133,4 +133,29 @@ Yes. NTT tokens can be used with chains that do not support NTT by leveraging th - **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism - **Messaging consistency** - the Token Bridge exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT -This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. \ No newline at end of file +This approach ensures interoperability while maintaining the integrity of the token's cross-chain movement. + +## How can I update my NTT CLI version? + +To update an existing NTT CLI installation, run the following command in your terminal: + +```bash +ntt update +``` + +NTT CLI installations and updates will always pick up the latest tag with name vX.Y.Z+cli and verify that the underlying commit is included in main. + +For local development, you can update your CLI version from a specific branch or install from a local path. + +To install from a specific branch, run: + +```bash +ntt update --branch foo +``` + +To install locally, run: +```bash +ntt update --path path/to/ntt/repo +``` + +Git branch and local installations enable a fast iteration loop as changes to the CLI code will immediately be reflected in the running binary without having to run any build steps. \ No newline at end of file diff --git a/products/native-token-transfers/guides/.pages b/products/native-token-transfers/guides/.pages index 19854a63c..69ca6f893 100644 --- a/products/native-token-transfers/guides/.pages +++ b/products/native-token-transfers/guides/.pages @@ -1,5 +1,7 @@ -title: Guides +title: Deployment Guides nav: - 'Deploy to EVM Chains': deploy-to-evm.md - 'Deploy to EVM Chains via Launchpad': evm-launchpad.md -- 'Deploy to Solana': deploy-to-solana.md \ No newline at end of file +- 'Deploy to Solana': deploy-to-solana.md +- 'Troubleshoot Your Deployment': troubleshoot.md +- 'Post Deployment': post-deployment.md \ No newline at end of file diff --git a/..build/transfers/native-token-transfers/deployment-process/post-deployment.md b/products/native-token-transfers/guides/post-deployment.md similarity index 100% rename from ..build/transfers/native-token-transfers/deployment-process/post-deployment.md rename to products/native-token-transfers/guides/post-deployment.md diff --git a/products/native-token-transfers/troubleshooting.md b/products/native-token-transfers/guides/troubleshoot.md similarity index 99% rename from products/native-token-transfers/troubleshooting.md rename to products/native-token-transfers/guides/troubleshoot.md index c2a2fd7ae..cc16efa19 100644 --- a/products/native-token-transfers/troubleshooting.md +++ b/products/native-token-transfers/guides/troubleshoot.md @@ -4,7 +4,7 @@ description: Resolve common issues in NTT deployment with this troubleshooting g categories: NTT, Transfer --- -# Troubleshooting NTT Deployment +# Troubleshoot Your NTT Deployment If you encounter issues during the NTT deployment process, check the following common points: diff --git a/products/native-token-transfers/overview.md b/products/native-token-transfers/overview.md index 059df7372..bd2181fcc 100644 --- a/products/native-token-transfers/overview.md +++ b/products/native-token-transfers/overview.md @@ -76,4 +76,4 @@ Here's a breakdown of the key steps involved when deploying NTT: Follow these steps to get started with NTT: -[timeline(wormhole-docs/.snippets/text/products/reference/ntt/overview/ntt-timeline.json)] \ No newline at end of file +[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] \ No newline at end of file diff --git a/products/native-token-transfers/reference/cli-commands.md b/products/native-token-transfers/reference/cli-commands.md index e5d1bbc85..4f2c705b6 100644 --- a/products/native-token-transfers/reference/cli-commands.md +++ b/products/native-token-transfers/reference/cli-commands.md @@ -10,7 +10,7 @@ categories: NTT, Transfer The NTT Command-Line Interface (CLI) is a powerful tool for managing native token transfers across multiple blockchain networks within the Wormhole ecosystem. This page provides a comprehensive list of available commands, their descriptions, and examples to help you interact with and configure the NTT system effectively. Whether initializing deployments, updating configurations, or working with specific chains, the NTT CLI simplifies these operations through its intuitive commands. -If you haven't installed the NTT CLI yet, follow the [NTT Installation Guide](TODO){target=\_blank} to set it up before proceeding. +If you haven't installed the NTT CLI yet, follow the [NTT Installation](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank} instructions to set it up before proceeding. ## Table of Commands @@ -20,33 +20,33 @@ To explore detailed information about any NTT CLI command, including its options ### General Commands -| Command | Description | Examples | -|-----------------------------------------|-------------------------------------------------------|--------------------------| -| `ntt update` | update the NTT CLI | `ntt update` | -| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | -| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest`| -| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0`| -| `ntt clone
    ` | initialize a deployment file from an existing contract| `ntt clone Mainnet Solana Sol5678...`| -| `ntt init ` | initialize a deployment file | `ntt init devnet` | -| `ntt pull` | pull the remote configuration | `ntt pull` | -| `ntt push` | push the local configuration | `ntt push` | -| `ntt status` | check the status of the deployment | `ntt status` | +| Command | Description | Example | +|-----------------------------------------|--------------------------------------------------------|--------------------------------------------------------------------| +| `ntt update` | update the NTT CLI | `ntt update` | +| `ntt new ` | create a new NTT project | `ntt new my-ntt-project` | +| `ntt add-chain ` | add a chain to the deployment file | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest` | +| `ntt upgrade ` | upgrade the contract on a specific chain | `ntt upgrade Solana --ver 1.1.0` | +| `ntt clone
    ` | initialize a deployment file from an existing contract | `ntt clone Mainnet Solana Sol5678...` | +| `ntt init ` | initialize a deployment file | `ntt init devnet` | +| `ntt pull` | pull the remote configuration | `ntt pull` | +| `ntt push` | push the local configuration | `ntt push` | +| `ntt status` | check the status of the deployment | `ntt status` | ### Configuration Commands -| Command | Description | Examples | -|---------------------------------------------|----------------------------------------|-------------------------------------| -| `ntt config set-chain `| set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key`| -| `ntt config unset-chain ` | unset a configuration value for a chain| `ntt config unset-chain Ethereum scan_api_key`| -| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key`| +| Command | Description | Example | +|----------------------------------------------|-----------------------------------------|------------------------------------------------| +| `ntt config set-chain ` | set a configuration value for a chain | `ntt config set-chain Ethereum scan_api_key` | +| `ntt config unset-chain ` | unset a configuration value for a chain | `ntt config unset-chain Ethereum scan_api_key` | +| `ntt config get-chain ` | get a configuration value for a chain | `ntt config get-chain Ethereum scan_api_key` | ### Solana Commands -| Command | Description | Examples | -|-----------------------------------------------|---------------------------------------------------------|------------------| -| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json`| -| `ntt solana token-authority ` | print the token authority address for a given program ID| `ntt solana token-authority Sol1234...`| -| `ntt solana ata `| print the token authority address for a given program ID| `ntt solana ata Mint123... Owner123... token22`| +| Command | Description | Example | +|------------------------------------------------|----------------------------------------------------------|-------------------------------------------------| +| `ntt solana key-base58 ` | print private key in base58 | `ntt solana key-base58 /path/to/keypair.json` | +| `ntt solana token-authority ` | print the token authority address for a given program ID | `ntt solana token-authority Sol1234...` | +| `ntt solana ata ` | print the token authority address for a given program ID | `ntt solana ata Mint123... Owner123... token22` | ## Where to Go Next diff --git a/..build/transfers/native-token-transfers/managers-transceivers.md b/products/native-token-transfers/reference/managers-transceivers.md similarity index 100% rename from ..build/transfers/native-token-transfers/managers-transceivers.md rename to products/native-token-transfers/reference/managers-transceivers.md diff --git a/products/products.md b/products/products.md index 2356ffba3..a2082851e 100644 --- a/products/products.md +++ b/products/products.md @@ -16,7 +16,7 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. -- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks +- [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks - [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages - [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods @@ -45,6 +45,10 @@ Wormhole offers different solutions for cross-chain asset transfer, each designe
    +In the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Token Bridge and how to select the best option for your use case: + +
    + Beyond asset transfers, Wormhole provides additional tools for cross-chain data and governance. ## Bridging UI diff --git a/..learn/glossary.md b/products/reference/glossary.md similarity index 100% rename from ..learn/glossary.md rename to products/reference/glossary.md diff --git a/products/token-bridge/guides/.pages b/products/token-bridge/guides/.pages index adacb8b94..52178f6c6 100644 --- a/products/token-bridge/guides/.pages +++ b/products/token-bridge/guides/.pages @@ -1,3 +1,3 @@ title: Guides nav: -- 'Transfer Wrapped Assets': transfer-wrapped-assets.md +- 'Interact with Contracts': token-bridge-contracts.md diff --git a/..build/transfers/token-bridge.md b/products/token-bridge/guides/token-bridge-contracts.md similarity index 99% rename from ..build/transfers/token-bridge.md rename to products/token-bridge/guides/token-bridge-contracts.md index b4eb849a5..567cb7601 100644 --- a/..build/transfers/token-bridge.md +++ b/products/token-bridge/guides/token-bridge-contracts.md @@ -4,7 +4,7 @@ description: Learn how to integrate Wormhole's Token Bridge for seamless multich categories: Token-Bridge, Transfer --- -# Token Bridge +# Interact with Token Bridge Contracts ## Introduction diff --git a/products/token-bridge/guides/transfer-wrapped-assets.md b/products/token-bridge/guides/transfer-wrapped-assets.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/token-bridge/guides/transfer-wrapped-assets.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/tools/.pages b/tools/.pages index 35c556581..71eb47ba5 100644 --- a/tools/.pages +++ b/tools/.pages @@ -2,5 +2,6 @@ title: Developer Tools nav: - typescript-sdk - solidity-sdk +- cli - 'Wormholescan Explorer': https://wormholescan.io/ - 'Wormholescan API': https://wormholescan.io/#/developers/api-doc \ No newline at end of file diff --git a/tools/cli/.pages b/tools/cli/.pages new file mode 100644 index 000000000..0987d7fe1 --- /dev/null +++ b/tools/cli/.pages @@ -0,0 +1,3 @@ +title: Wormhole CLI +nav: +- 'Get Started': get-started.md diff --git a/..build/toolkit/cli.md b/tools/cli/get-started.md similarity index 83% rename from ..build/toolkit/cli.md rename to tools/cli/get-started.md index 74ffc7436..cd2d66b9c 100644 --- a/..build/toolkit/cli.md +++ b/tools/cli/get-started.md @@ -55,89 +55,88 @@ Options: ### Subcommands -??? code "Aptos" +??? interface "Aptos" ```bash - --8<-- 'code/build/toolkit/cli/aptos.txt' + --8<-- 'code/tools/cli/get-started/aptos.txt' ``` -??? code "Edit VAA" +??? interface "Edit VAA" ```bash - --8<-- 'code/build/toolkit/cli/edit-vaa.txt' + --8<-- 'code/tools/cli/get-started/edit-vaa.txt' ``` -??? code "EVM" +??? interface "EVM" ```bash - --8<-- 'code/build/toolkit/cli/evm.txt' + --8<-- 'code/tools/cli/get-started/evm.txt' ``` -??? code "Generate" +??? interface "Generate" ```bash - --8<-- 'code/build/toolkit/cli/generate.txt' + --8<-- 'code/tools/cli/get-started/generate.txt' ``` -??? code "Info" +??? interface "Info" ```bash - --8<-- 'code/build/toolkit/cli/info.txt' + --8<-- 'code/tools/cli/get-started/info.txt' ``` -??? code "NEAR" +??? interface "NEAR" ```bash - --8<-- 'code/build/toolkit/cli/near.txt' + --8<-- 'code/tools/cli/get-started/near.txt' ``` -??? code "Parse" +??? interface "Parse" ```bash - --8<-- 'code/build/toolkit/cli/parse.txt' + --8<-- 'code/tools/cli/get-started/parse.txt' ``` -??? code "Recover" +??? interface "Recover" ```bash - --8<-- 'code/build/toolkit/cli/recover.txt' + --8<-- 'code/tools/cli/get-started/recover.txt' ``` -??? code "Status" +??? interface "Status" ```bash - --8<-- 'code/build/toolkit/cli/status.txt' + --8<-- 'code/tools/cli/get-started/status.txt' ``` -??? code "Submit" +??? interface "Submit" ```bash - --8<-- 'code/build/toolkit/cli/submit.txt' + --8<-- 'code/tools/cli/get-started/submit.txt' ``` -??? code "Sui" +??? interface "Sui" ```bash - --8<-- 'code/build/toolkit/cli/sui.txt' + --8<-- 'code/tools/cli/get-started/sui.txt' ``` -??? code "Transfer" +??? interface "Transfer" ```bash - --8<-- 'code/build/toolkit/cli/transfer.txt' + --8<-- 'code/tools/cli/get-started/transfer.txt' ``` -??? code "Verify VAA" +??? interface "Verify VAA" ```bash - --8<-- 'code/build/toolkit/cli/verify-vaa.txt' + --8<-- 'code/tools/cli/get-started/verify-vaa.txt' ``` - ## Examples -### VAA generation +### Generate a VAA Use `generate` to create VAAs for testing. For example, use the following command to create an NFT bridge registration VAA: ```bash ---8<-- 'code/build/toolkit/cli/vaa-generation-example.txt' +--8<-- 'code/tools/cli/get-started/vaa-generation-example.txt' ``` The below example generates a token attestation VAA: ```bash ---8<-- 'code/build/toolkit/cli/token-attestation-vaa.txt' +--8<-- 'code/tools/cli/get-started/token-attestation-vaa.txt' ``` -### VAA parsing +### Parse a VAA Use `parse` to parse a VAA into JSON: @@ -148,10 +147,10 @@ worm parse $(worm-fetch-governance 13940208096455381020) This example will fetch governance VAA `13940208096455381020` and print it as JSON: ```bash ---8<-- 'code/build/toolkit/cli/fetch-vaa-example.txt' +--8<-- 'code/tools/cli/get-started/fetch-vaa-example.txt' ``` -### Submitting VAAs +### Submit VAAs Use `submit` to submit a VAA to a chain. It first parses the VAA and determines the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`): @@ -162,12 +161,12 @@ worm submit $(cat my-nft-registration.txt) --network mainnet The script will ask you to specify the target chain for VAAs that don't have a specific target chain (like registrations or Guardian set upgrades). For example, to submit a Guardian set upgrade on all chains, simply run: ```bash ---8<-- 'code/build/toolkit/cli/guardian-upgrade.txt' +--8<-- 'code/tools/cli/get-started/guardian-upgrade.txt' ``` The VAA payload type (Guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there. -### Getting Info +### Fetch Contract Information To get info about a contract (only EVM supported at this time), use the following command: @@ -178,11 +177,9 @@ worm evm info -c bsc -n mainnet -m TokenBridge Running this command generates the following output: ```bash ---8<-- 'code/build/toolkit/cli/info-response.txt' +--8<-- 'code/tools/cli/get-started/info-response.txt' ``` -### Additional Info Examples - You can get the contract address for a module as follows: ```bash @@ -195,6 +192,8 @@ To get the contract address for `NFTBridge` on BSC Mainnet, for example, you can worm info contract mainnet bsc NFTBridge ``` +### Fetch Chain Information + You can get the RPC address for a chain as follows: ```bash @@ -206,4 +205,3 @@ To get the RPC address for BSC Mainnet, for example, you can provide the followi ```bash worm info rpc mainnet bsc ``` - diff --git a/..build/toolkit/dev-env.md b/tools/dev-env.md similarity index 100% rename from ..build/toolkit/dev-env.md rename to tools/dev-env.md diff --git a/..build/toolkit/faqs.md b/tools/faqs.md similarity index 100% rename from ..build/toolkit/faqs.md rename to tools/faqs.md From 543a4d71e8d4c3bc3d22dbb6ed0a7073df3e4bbc Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 10:01:48 -0400 Subject: [PATCH 37/55] Update the TypeScript SDK section (#433) * update typescript sdk section * add link to source code * clean up links * delete overview --- .../typescript-sdk/sdk-reference/tokens.ts | 5 +- tools/typescript-sdk/get-started.md | 142 +++++---- tools/typescript-sdk/sdk-reference.md | 287 ++++++------------ 3 files changed, 182 insertions(+), 252 deletions(-) diff --git a/.snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts b/.snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts index 4298b7020..362668b6a 100644 --- a/.snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts +++ b/.snippets/code/tools/typescript-sdk/sdk-reference/tokens.ts @@ -1,5 +1,6 @@ +// Get the TokenId for an ERC-20 token const sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...'); - +// Get the TokenId for native ETH const gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native'); - +// Convert a TokenId back to a string const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' \ No newline at end of file diff --git a/tools/typescript-sdk/get-started.md b/tools/typescript-sdk/get-started.md index 550a7490a..082591d29 100644 --- a/tools/typescript-sdk/get-started.md +++ b/tools/typescript-sdk/get-started.md @@ -14,55 +14,6 @@ This guide helps you install the SDK, initialize a `Wormhole` instance to suppor If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). -## Prerequisites - -Before you begin, make sure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed - -??? example "Project setup instructions" - - Use the following commands to create a TypeScript project: - - 1. Create a directory and initialize a Node.js project: - - ```bash - mkdir wh-ts-demo - cd wh-ts-demo - npm init -y - ``` - - 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: - - ```bash - npm install --save-dev tsx typescript @types/node - ``` - - 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: - - ```bash - npx tsc --init - ``` - - Make sure your `tsconfig.json` includes the following settings: - - ```json - { - "compilerOptions": { - // es2020 or newer - "target": "es2020", - // Use esnext if you configured your package.json with type: "module" - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } - } - ``` - ## Install the SDK To install the Wormhole TypeScript SDK, use the following command: @@ -132,24 +83,93 @@ npm install @wormhole-foundation/sdk-evm ## Initialize the SDK -You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. +Getting your integration started is simple. First, import Wormhole: -1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: +```ts +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts::1' +``` - ```bash - mkdir src - touch src/main.ts - ``` +Then, import each of the ecosystem [platforms](/docs/tools/typescript-sdk/sdk-reference/#platforms) that you wish to support: -2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: +```ts +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:4:9' +``` - ```ts title="src/main.ts" - --8<-- "code/tools/typescript-sdk/get-started/snippet-1.ts" - ``` +To make the [platform](/docs/tools/typescript-sdk/sdk-reference/#platforms) modules available for use, pass them to the Wormhole constructor and specify the network (`Mainnet`, `Testnet`, or `Devnet`) you want to interact with: + +```ts +--8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:13:20' +``` + +With a configured `Wormhole` object, you can begin to interact with these chains. -## Fetch Chain Information +## Example Usage + +Follow these steps to confirm that the SDK is initialized correctly and can fetch basic chain information for your target chains. + +### Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript, `tsx` (for running TypeScript files), Node.js type definitions, the base Wormhole SDK, and the platform-specific packages for the chains you want to interact with: + + ```bash + npm install --save-dev tsx typescript @types/node @wormhole-foundation/sdk @wormhole-foundation/sdk-evm @wormhole-foundation/sdk-solana + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + + 4. Initialize the main `Wormhole` class to use the SDK. Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + + 5. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + --8<-- "code/tools/typescript-sdk/get-started/snippet-1.ts" + ``` -Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. +### Fetch Chain Information 1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: diff --git a/tools/typescript-sdk/sdk-reference.md b/tools/typescript-sdk/sdk-reference.md index 63bb1a1ef..262d09771 100644 --- a/tools/typescript-sdk/sdk-reference.md +++ b/tools/typescript-sdk/sdk-reference.md @@ -4,14 +4,9 @@ description: Explore Wormhole's TypeScript SDK and learn how to perform differen categories: Typescript-SDK --- -# Wormhole TypeScript SDK - -## Introduction - -The Wormhole TypeScript SDK is useful for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole. This package bundles together functions, definitions, and constants that streamline the process of connecting chains and completing transfers using Wormhole. The SDK also offers targeted sub-packages for Wormhole-connected platforms, which allow you to add multichain support without creating outsized dependencies. - -This section covers all you need to know about the functionality and ease of development offered through the Wormhole TypeScript SDK. Take a tour of the package to discover how it helps make integration easier. Learn more about how the SDK abstracts away complexities around concepts like platforms, contexts, and signers. Finally, you'll find guidance on usage, along with code examples, to show you how to use the tools of the SDK. +# Wormhole TypeScript SDK Reference +This page covers all you need to know about the functionality offered through the Wormhole TypeScript SDK.
    @@ -19,165 +14,76 @@ This section covers all you need to know about the functionality and ease of dev --- - Find installation instructions for both the meta package and installing specific, individual packages + Find installation instructions for both the meta package and installing specific, individual packages. - [:custom-arrow: Install the SDK](#installation) - -- :octicons-book-16:{ .lg .middle } **Concepts** - - --- + [:custom-arrow: Install the SDK](/docs/tools/typescript-sdk/get-started/#install-the-sdk) - Understand key concepts and how the SDK abstracts them away. Learn more about platforms, chain context, addresses, and signers - - [:custom-arrow: Explore concepts](#concepts) - -- :octicons-file-code-16:{ .lg .middle } **Usage** +- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** --- - Guidance on using the SDK to add seamless interchain messaging to your application, including code examples + Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at available methods, classes, interfaces, and definitions. - [:custom-arrow: Use the SDK](#usage) + [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} -- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** +- :octicons-code-square-16:{ .lg .middle } **Source Code** --- - Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at availabel methods, classes, interfaces, and definitions - - [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} + Want to go straight to the source? Check out the TypeScript SDK GitHub repository. + + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/){target=\_blank}
    !!! warning - This package is a work in progress. The interface may change, and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} any issues you find. - -## Installation - -### Basic - -To install the meta package using npm, run the following command in the root directory of your project: - -```bash -npm install @wormhole-foundation/sdk -``` - -This package combines all the individual packages to make setup easier while allowing for tree shaking. - -### Advanced - -Alternatively, you can install a specific set of published packages individually: - -??? interface "`sdk-base` - exposes constants" - - ```sh - npm install @wormhole-foundation/sdk-base - ``` - -??? interface "`sdk-definitions` - exposes contract interfaces, basic types, and VAA payload definitions" - - ```sh - npm install @wormhole-foundation/sdk-definitions - ``` - -??? interface "`sdk-evm` - exposes EVM-specific utilities" - - ```sh - npm install @wormhole-foundation/sdk-evm - ``` - -??? interface "`sdk-evm-tokenbridge` - exposes the EVM Token Bridge protocol client" - - ```sh - npm install @wormhole-foundation/sdk-evm-tokenbridge - ``` - -## Usage - -Getting your integration started is simple. First, import Wormhole: - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts::1' -``` - -Then, import each of the ecosystem [platforms](#platforms) that you wish to support: - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:4:9' -``` - - -To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:13:20' -``` - -With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:22:22' -``` - -You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts:54:61' -``` - -??? code "View the complete script" - ```ts - --8<-- 'code/tools/typescript-sdk/sdk-reference/get-vaa.ts' - ``` - -Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. - -```ts ---8<-- 'code/tools/typescript-sdk/sdk-reference/config-override.ts' -``` - -??? code "View the complete script" - ```ts - --8<-- 'code/tools/typescript-sdk/sdk-reference/config.ts' - ``` + This package is a work in progress. The interface may change, and there are likely bugs. Please [report any issues](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} you find. ## Concepts -Understanding several higher-level Wormhole concepts and how the SDK abstracts them away will help you use the tools most effectively. The following sections will introduce and discuss the concepts of platforms, chain contexts, addresses, signers, and protocols, how they are used in the Wormhole context, and how the SDK helps ease development in each conceptual area. +Understanding key Wormhole concepts—and how the SDK abstracts them—will help you use the tools more effectively. The following sections cover platforms, chain contexts, addresses, signers, and protocols, explaining their roles in Wormhole and how the SDK simplifies working with them. ### Platforms -While every chain has unique attributes, chains from the same platform typically have standard functionalities they share. The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: +The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: -- Protocols, such as [Wormhole core](#wormhole-core), preconfigured to suit the selected platform +- [Protocols](#protocols) preconfigured to suit the selected platform - Definitions and configurations for types, signers, addresses, and chains - Helpers configured for dealing with unsigned transactions on the selected platform -These modules also import and expose essential functions and define types or constants from the chain's native ecosystem to reduce the dependencies needed to interact with a chain using Wormhole. Rather than installing the entire native package for each desired platform, you can install a targeted package of standardized functions and definitions essential to connecting with Wormhole, keeping project dependencies as slim as possible. - +These modules expose key functions and types from the native ecosystem, reducing the need for full packages and keeping dependencies lightweight. -Wormhole currently supports the following platforms: +??? interface "Supported platform modules" -- EVM -- Solana -- Cosmos -- Sui -- Aptos -- Algorand + | Platform | Installation Command | + |----------|----------------------------------------------------| + | EVM |
    ```@wormhole-foundation/sdk-evm```
    | + | Solana |
    ```@wormhole-foundation/sdk-solana```
    | + | Algorand |
    ```@wormhole-foundation/sdk-algorand```
    | + | Aptos |
    ```@wormhole-foundation/sdk-aptos```
    | + | Cosmos |
    ```@wormhole-foundation/sdk-cosmwasm```
    | + | Sui |
    ```@wormhole-foundation/sdk-sui```
    | -See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. + See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. ### Chain Context -The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. +`ChainContext` (from the `@wormhole-foundation/sdk-definitions` package) provides a unified interface for interacting with connected chains. It: + +- Holds network, chain, and platform configurations +- Caches RPC and protocol clients +- Exposes both platform-inherited and chain-specific methods +- Defines the core types used across the SDK: `Network`, `Chain`, and `Platform` ```ts +// Get the chain context for the source and destination chains +// This is useful to grab direct clients for the protocols --8<-- 'code/tools/typescript-sdk/sdk-reference/get-chain.ts' ``` ### Addresses -The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. +The SDK uses the `UniversalAddress` class to implement the `Address` interface, standardizing address handling across chains. All addresses are parsed into a 32-byte format. Each platform also defines a `NativeAddress` type that understands its native format. These abstractions ensure consistent cross-chain address handling. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/addresses.ts' @@ -185,11 +91,7 @@ The SDK uses the `UniversalAddress` class to implement the `Address` interface, ### Tokens -Similar to the `ChainAddress` type, the `TokenId` type provides the chain and address of a given token. The following snippet introduces `TokenId`, a way to uniquely identify any token, whether it's a standard token or a blockchain's native currency (like ETH for Ethereum). - -Wormhole uses their contract address to create a `TokenId` for standard tokens. For native currencies, Wormhole uses the keyword `native` instead of an address. This makes it easy to work with any type of token consistently. - -Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. +The `TokenId` type identifies any token by its chain and address. For standardized tokens, Wormhole uses the token's contract address. For native currencies (e.g., ETH on Ethereum), it uses the keyword `native`. This ensures consistent handling of all tokens. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/tokens.ts' @@ -197,11 +99,10 @@ Finally, the snippet demonstrates how to convert a `TokenId` back into a regular ### Signers -Certain methods of signing transactions require a `Signer` interface in the SDK. Depending on the specific requirements, this interface can be fulfilled by either a `SignOnlySigner` or a `SignAndSendSigner`. A signer can be created by wrapping an offline or web wallet. - -A `SignOnlySigner` is used when the signer isn't connected to the network or prefers not to broadcast transactions themselves. It accepts an array of unsigned transactions and returns an array of signed and serialized transactions. Before signing, the transactions may be inspected or altered. It's important to note that the serialization process is chain-specific. Refer to the testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank} or [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for an example of how to implement a signer for a specific chain or platform. +The SDK's `Signer` interface can be implemented as either a `SignOnlySigner` or a `SignAndSendSigner`, created by wrapping an offline or web wallet: -Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. +- **`SignOnlySigner`**: Signs and serializes unsigned transactions without broadcasting them. Transactions can be inspected or modified before signing. Serialization is chain-specific. See testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank}, [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for implementation examples. +- **`SignAndSendSigner`**: Signs and broadcasts transactions, returning their transaction IDs in order. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/signers.ts' @@ -209,53 +110,69 @@ Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to #### Set Up a Signer with Ethers.js -To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: +To sign transactions programmatically with the Wormhole SDK, you can use [Ethers.js](https://docs.ethers.org/){target=\_blank} to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: ```javascript --8<-- 'code/tools/typescript-sdk/sdk-reference/ethers.js' ``` - - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions - - - **`signer`** - represents the account that will sign the transaction. In this case, you’re creating a signer using the private key associated with the account. The signer is responsible for authorizing transactions by digitally signing them with the private key - - - **`Wallet`** - combines both the provider (for blockchain interaction) and the signer (for transaction authorization), allowing you to sign and send transactions programmatically +These components work together to create, sign, and submit a transaction to the blockchain: -These components work together to create, sign, and submit a transaction to the blockchain. - -???- tip "Managing Private Keys Securely" - Handling private keys is unavoidable, so it’s crucial to manage them securely. Here are some best practices: - - - **Use environment variables** - avoid hardcoding private keys in your code. Use environment variables or secret management tools to inject private keys securely - - **Hardware wallets** - for production environments, consider integrating hardware wallets to keep private keys secure while allowing programmatic access through the SDK +- **`provider`**: Connects to the Ethereum or EVM-compatible network, enabling data access and transaction submission. +- **`signer`** : Represents the account that signs transactions using a private key. +- **`Wallet`**: Combines provider and signer to create, sign, and send transactions programmatically. ### Protocols -While Wormhole is a Generic Message Passing (GMP) protocol, several protocols have been built to provide specific functionality. If available, each protocol will have a platform-specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain. - -#### Wormhole Core - -The core protocol underlies all Wormhole activity. This protocol is responsible for emitting the message containing the information necessary to perform bridging, including the [emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter){target=\_blank}, the [sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence){target=\_blank} for the message, and the payload of the message itself. +Wormhole is a Generic Message Passing (GMP) protocol with several specialized protocols built on top. Each protocol has platform-specific implementations providing methods to generate transactions or read on-chain state. + +??? interface "Supported protocol modules" + + | Protocol | Installation Command | + |-----------------------|----------------------------------------------------------------| + | EVM Core |
    ```@wormhole-foundation/sdk-evm-core```
    | + | EVM Token Bridge |
    ```@wormhole-foundation/sdk-evm-tokenbridge```
    | + | EVM CCTP |
    ```@wormhole-foundation/sdk-evm-cctp```
    | + | EVM Portico |
    ```@wormhole-foundation/sdk-evm-portico```
    | + | EVM TBTC |
    ```@wormhole-foundation/sdk-evm-tbtc```
    | + | Solana Core |
    ```@wormhole-foundation/sdk-solana-core```
    | + | Solana Token Bridge |
    ```@wormhole-foundation/sdk-solana-tokenbridge```
    | + | Solana CCTP |
    ```@wormhole-foundation/sdk-solana-cctp```
    | + | Solana TBTC |
    ```@wormhole-foundation/sdk-solana-tbtc```
    | + | Algorand Core |
    ```@wormhole-foundation/sdk-algorand-core```
    | + | Algorand Token Bridge |
    ```@wormhole-foundation/sdk-algorand-tokenbridge```
    | + | Aptos Core |
    ```@wormhole-foundation/sdk-aptos-core```
    | + | Aptos Token Bridge |
    ```@wormhole-foundation/sdk-aptos-tokenbridge```
    | + | Aptos CCTP |
    ```@wormhole-foundation/sdk-aptos-cctp```
    | + | Cosmos Core |
    ```@wormhole-foundation/sdk-cosmwasm-core```
    | + | Cosmos Token Bridge |
    ```@wormhole-foundation/sdk-cosmwasm-tokenbridge```
    | + | Sui Core |
    ```@wormhole-foundation/sdk-sui-core```
    | + | Sui Token Bridge |
    ```@wormhole-foundation/sdk-sui-tokenbridge```
    | + | Sui CCTP |
    ```@wormhole-foundation/sdk-sui-cctp```
    | -The following example demonstrates sending and verifying a message using the Wormhole Core protocol on Solana. -First, initialize a Wormhole instance for the Testnet environment, specifically for the Solana chain. Then, obtain a signer and its associated address, which will be used to sign transactions. +#### Wormhole Core -Next, get a reference to the core messaging bridge, which is the main interface for interacting with Wormhole's cross-chain messaging capabilities. -The code then prepares a message for publication. This message includes: +The core protocol powers all Wormhole activity by emitting messages containing the [emitter address](/docs/products/reference/glossary/#emitter){target=\_blank}, sequence number, and payload needed for bridging. -- The sender's address -- The message payload (in this case, the encoded string `lol`) -- A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +Example workflow on Solana Testnet: -After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. +1. Initialize a Wormhole instance for Solana. +2. Obtain a signer and its address. +3. Access the core messaging bridge for cross-chain messaging. +4. Prepare a message with: -The code then waits for the Wormhole network to process and sign the message, turning it into a Verified Action Approval (VAA). This VAA is retrieved in a `Uint8Array` format, with a timeout of 60 seconds. + - Sender's address + - Encoded payload (e.g., "lol") + - Nonce (e.g., 0) + - Consistency level (e.g., 0) -Lastly, the code will demonstrate how to verify the message on the receiving end. A verification transaction is prepared using the original sender's address and the VAA, and finally, this transaction is signed and sent. +5. Generate, sign, and send the transaction to publish the message. +6. Extract the Wormhole message ID from transaction logs for tracking. +7. Wait (up to 60s) to receive the [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} (in `Uint8Array` format) from the Wormhole network. +8. Prepare and send a verification transaction on the receiving chain using the sender's address and the VAA. -???+ code "View the complete script" +???+ example "Example workflow" ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/example-core-bridge.ts' ``` @@ -264,14 +181,12 @@ The payload contains the information necessary to perform whatever action is req #### Token Bridge -The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. +The most familiar protocol built on Wormhole is the Token Bridge. Each supported chain has a `TokenBridge` client that provides a consistent interface for transferring tokens and handling attestations. While `WormholeTransfer` abstractions are recommended, direct interaction with the protocol is also supported. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge-snippet.ts' ``` -Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. - ## Transfers While using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens. @@ -280,17 +195,15 @@ The `WormholeTransfer` interface provides a convenient abstraction to encapsulat ### Token Transfers -Performing a token transfer is trivial for any source and destination chains. You can create a new `Wormhole` object to make objects like `TokenTransfer` and `CircleTransfer`, to transfer tokens between chains. - -The following example demonstrates the process of initiating and completing a token transfer. It starts by creating a `TokenTransfer` object, which tracks the transfer's state throughout its lifecycle. The code then obtains a quote for the transfer, ensuring the amount is sufficient to cover fees and any requested native gas. +Token transfers between chains are straightforward using Wormhole. Create a `Wormhole` instance and use it to initialize a `TokenTransfer` or `CircleTransfer` object. -The transfer process is divided into three main steps: +The example below shows how to initiate and complete a `TokenTransfer`. After creating the transfer object and retrieving a quote (to verify sufficient amount and fees), the process involves: -1. Initiating the transfer on the source chain -2. Waiting for the transfer to be attested (if not automatic) -3. Completing the transfer on the destination chain +1. Initiating the transfer on the source chain. +2. Waiting for attestation (if required). +3. Completing the transfer on the destination chain. -For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. +For automatic transfers, the process ends after initiation. Manual transfers require attestation before completion. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge.ts:120:158' @@ -301,17 +214,15 @@ For automatic transfers, the process ends after initiation. The code waits for t --8<-- 'code/tools/typescript-sdk/sdk-reference/token-bridge.ts' ``` -Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. +Internally, this uses the [`TokenBridge`](#token-bridge) protocol client to transfer tokens. ### Native USDC Transfers -You can also transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. Please note that if the transfer is set to `Automatic` mode, a fee for performing the relay will be included in the quote. This fee is deducted from the total amount requested to be sent. For example, if the user wishes to receive `1.0` on the destination, the amount sent should be adjusted to `1.0` plus the relay fee. The same principle applies to native gas drop offs. +You can transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. If the transfer is set to `automatic`, the quote will include a relay fee, which is deducted from the total amount sent. For example, to receive 1.0 USDC on the destination chain, the sender must cover both the 1.0 and the relay fee. The same applies when including a native gas drop-off. -In the following example, the `wh.circleTransfer` function is called with several parameters to set up the transfer. It takes the amount to be transferred (in the token's base units), the sender's chain and address, and the receiver's chain and address. The function also allows specifying whether the transfer should be automatic, meaning it will be completed without further user intervention. +In the example below, the `wh.circleTransfer` function is used to initiate the transfer. It accepts the amount (in base units), sender and receiver chains and addresses, and an optional automatic flag to enable hands-free completion. You can also include an optional payload (set to `undefined` here) and specify a native gas drop-off if desired. -An optional payload can be included with the transfer, though it's set to undefined in this case. Finally, if the transfer is automatic, you can request that native gas (the blockchain's native currency used for transaction fees) be sent to the receiver along with the transferred tokens. - -When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. +When waiting for the VAA, a timeout of `60,000` milliseconds is used. The actual wait time [varies by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/cctp.ts:69:112' @@ -359,11 +270,9 @@ Once the tokens are selected, a `RouteTransferRequest` may be created to provide --8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:55:67' ``` -Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - -After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. +Choosing the best route is up to the developer and may involve sorting by output amount or estimated completion time (though no estimate is currently provided). -After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. +Once a route is selected, parameters like `amount`, `nativeGasDropoff`, and `slippage` can be set. After validation, a transfer quote is requested, including fees, estimated time, and final amount. If successful, the quote is shown to the user for review before proceeding, ensuring all details are verified prior to transfer. ```ts --8<-- 'code/tools/typescript-sdk/sdk-reference/router.ts:72:93' From f7b307d05e0c011ba8f3ff7465080b2139fbcb46 Mon Sep 17 00:00:00 2001 From: Martin Hofmann Date: Fri, 30 May 2025 16:07:25 +0200 Subject: [PATCH 38/55] Settlement - Get Started page (#378) * get started page for settlement * update wording based on feedback * add link and update wording * update next step links * update styling * update words * update table and intro * update next steps * link to sdk * initial demo mayan swift content * demo-mayan swift * minor fixes * Apply suggestions from code review Co-authored-by: Erin Shaben Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * applied feedback * Apply suggestions from code review Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria Enache Co-authored-by: Ilaria <43253244+ilariae@users.noreply.github.com> Co-authored-by: Erin Shaben Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../settlement/get-started/snippet-1.ts | 50 ++++++++ .../settlement/get-started/snippet-2.ts | 82 +++++++++++++ .../settlement/get-started/snippet-3.html | 13 ++ products/settlement/get-started.md | 112 +++++++++++++++++- 4 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 .snippets/code/products/settlement/get-started/snippet-1.ts create mode 100644 .snippets/code/products/settlement/get-started/snippet-2.ts create mode 100644 .snippets/code/products/settlement/get-started/snippet-3.html diff --git a/.snippets/code/products/settlement/get-started/snippet-1.ts b/.snippets/code/products/settlement/get-started/snippet-1.ts new file mode 100644 index 000000000..2815dc1fa --- /dev/null +++ b/.snippets/code/products/settlement/get-started/snippet-1.ts @@ -0,0 +1,50 @@ +import { + Chain, + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, +} from '@wormhole-foundation/sdk-connect'; +import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm'; +import { getSolanaSigner } from '@wormhole-foundation/sdk-solana'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (MAINNET_ETH_PRIVATE_KEY, MAINNET_SOL_PRIVATE_KEY) + * must be loaded securely beforehand, for example via a keystore, + * secrets manager, or environment variables (not recommended). + */ +// Define Transfer Interface +export interface SignerContext { + signer: Signer; + address: ChainAddress; +} + +export async function getSigner( + chain: ChainContext +): Promise> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + switch (platform) { + case 'Solana': + signer = await getSolanaSigner( + await chain.getRpc(), + getEnv('MAINNET_SOL_PRIVATE_KEY') + ); + break; + case 'Evm': + signer = await getEvmSignerForKey( + await chain.getRpc(), + getEnv('MAINNET_ETH_PRIVATE_KEY') + ); + break; + default: + throw new Error('Unrecognized platform: ' + platform); + } + + return { + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} diff --git a/.snippets/code/products/settlement/get-started/snippet-2.ts b/.snippets/code/products/settlement/get-started/snippet-2.ts new file mode 100644 index 000000000..e4d7cfeac --- /dev/null +++ b/.snippets/code/products/settlement/get-started/snippet-2.ts @@ -0,0 +1,82 @@ +import { Wormhole, routes } from '@wormhole-foundation/sdk-connect'; +import { EvmPlatform } from '@wormhole-foundation/sdk-evm'; +import { SolanaPlatform } from '@wormhole-foundation/sdk-solana'; +import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route'; +import { getSigner } from './helpers'; + +(async function () { + // Setup + const wh = new Wormhole('Mainnet', [EvmPlatform, SolanaPlatform]); + + const sendChain = wh.getChain('Ethereum'); + const destChain = wh.getChain('Solana'); + + // To transfer native ETH on Ethereum to native SOL on Solana + const source = Wormhole.tokenId(sendChain.chain, 'native'); + const destination = Wormhole.tokenId(destChain.chain, 'native'); + + // Create a new Wormhole route resolver, adding the Mayan route to the default list + // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type, + // but MayanRouteSWIFT is compatible and works as intended in this context. + const resolver = wh.resolver([MayanRouteSWIFT]); + + // Show supported tokens + const dstTokens = await resolver.supportedDestinationTokens( + source, + sendChain, + destChain + ); + console.log(dstTokens.slice(0, 5)); + + // Load signers and addresses from helpers + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); + + // Creating a transfer request fetches token details + // since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source, + destination, + }); + + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + const bestRoute = foundRoutes[0]!; + + // Specify the amount as a decimal string + const transferParams = { + amount: '0.002', + options: bestRoute.getDefaultOptions(), + }; + + // Validate the queries route + let validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) { + console.error(validated.error); + return; + } + console.log('Validated: ', validated); + + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) { + console.error(`Error fetching a quote: ${quote.error.message}`); + return; + } + console.log('Quote: ', quote); + + // Initiate the transfer + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); + + await routes.checkAndCompleteTransfer( + bestRoute, + receipt, + receiver.signer, + 15 * 60 * 1000 + ); +})(); diff --git a/.snippets/code/products/settlement/get-started/snippet-3.html b/.snippets/code/products/settlement/get-started/snippet-3.html new file mode 100644 index 000000000..718db10f3 --- /dev/null +++ b/.snippets/code/products/settlement/get-started/snippet-3.html @@ -0,0 +1,13 @@ +
    + npx tsx src/swap.ts + Validated: { valid: true, ... } + Quote: { success: true, ... } + Initiated transfer with receipt: ... + Checking transfer state... + Current Transfer State: SourceInitiated + Current Transfer State: SourceInitiated + Current Transfer State: SourceInitiated + Current Transfer State: DestinationFinalized + +
    + diff --git a/products/settlement/get-started.md b/products/settlement/get-started.md index 30404ce4c..29c56b48a 100644 --- a/products/settlement/get-started.md +++ b/products/settlement/get-started.md @@ -1 +1,111 @@ -TODO \ No newline at end of file +--- +title: Get Started +description: Perform a cross-chain token swap using Wormhole Settlement and the Mayan Swift route with the TypeScript SDK on mainnet. +categories: Settlement, Transfer +--- + +# Get Started + +[Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. + +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. + +By the end, you'll have a working script that: + +- Resolves token transfer routes using Mayan Swift +- Quotes and validates the best route +- Initiates a swap on a source chain and completes the transfer on a destination chain + +!!! note + Mayan Swift currently supports **mainnet only**. Attempting to run this demo on a testnet will fail. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#settlement){target=\_blank} + +This example uses Ethereum as the source chain and Solana as the destination. As a result, you'll need an Ethereum wallet with ETH for gas and a Solana wallet with SOL for fees. You can adapt the example to match your preferred chains. + +## Set Up a Project + +Start by scaffolding a basic Node.js project and installing the required SDKs. + +1. Create a new project folder: + + ```bash + mkdir settlement-swap + cd settlement-swap + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk-connect \ + @wormhole-foundation/sdk-evm \ + @wormhole-foundation/sdk-solana \ + @mayanfinance/wormhole-sdk-route \ + dotenv + npm install -D typescript tsx + ``` + +3. Create the file structure: + + ```bash + mkdir src + touch src/helpers.ts src/swap.ts .env .gitignore + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `MAINNET_ETH_PRIVATE_KEY` and `MAINNET_SOL_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [cast wallet](https://book.getfoundry.sh/reference/cast/cast-wallet/){target=_blank}. + + !!! warning + If you use a .env file during development, add it to your .gitignore to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Swap + +This section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source and destination chain signers. + +Then, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and completes the transfer on Solana. + +1. Open `helper.ts` and define the `getSigner` utility function to load private keys, instantiate signers for Ethereum and Solana, and return the signers along with the Wormhole-formatted address: + + ```ts title="src/helpers.ts" + --8<-- "code/products/settlement/get-started/snippet-1.ts" + ``` + +2. In `swap.ts`, add the following script, which will handle all of the logic required to perform the token swap: + + ```ts title="src/swap.ts" + --8<-- "code/products/settlement/get-started/snippet-2.ts" + ``` + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx src/swap.ts + ``` + + If successful, you’ll see terminal output like this: + + --8<-- "code/products/settlement/get-started/snippet-3.html" + +Congratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement. + +## Customize the Integration + +You can tailor the example to your use case by adjusting: + +- **Tokens and chains**: Use `getSupportedTokens()` to explore what's available. +- **Source and destination chains**: Modify `sendChain` and `destChain` in `swap.ts`. +- **Transfer settings**: Update the amount or route parameters. +- **Signer management**: Modify `src/helpers.ts` to integrate with your preferred wallet setup. + +## Next Steps + +Once you've chosen a path, follow the corresponding guide to start building: + +- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. + From 8870c49ffa8cad33ec1c6e95270ccb465db4cc22 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Fri, 30 May 2025 16:08:20 +0200 Subject: [PATCH 39/55] use queries page (#432) * use queries page * update snippets --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- .../use-queries/eth-call-initial-request.txt | 1 + .../use-queries/eth-call-initial-response.txt | 5 + .../queries/guides/use-queries/query-demo.sol | 137 +++++++++++++++ .../query-proxy-query-response.jsx | 4 + .../query-request-with-api-key.jsx | 9 + .../queries/guides/use-queries/test-full.jsx | 65 +++++++ .../products/queries/queries-timeline.json | 6 +- products/queries/guides/.pages | 6 +- products/queries/guides/construct-a-query.md | 1 - products/queries/guides/mock-a-query.md | 1 - products/queries/guides/query-request.md | 1 - products/queries/guides/submit-response.md | 1 - products/queries/guides/use-queries.md | 160 ++++++++++++++++++ products/queries/guides/verify-response.md | 1 - 14 files changed, 385 insertions(+), 13 deletions(-) create mode 100644 .snippets/code/products/queries/guides/use-queries/eth-call-initial-request.txt create mode 100644 .snippets/code/products/queries/guides/use-queries/eth-call-initial-response.txt create mode 100644 .snippets/code/products/queries/guides/use-queries/query-demo.sol create mode 100644 .snippets/code/products/queries/guides/use-queries/query-proxy-query-response.jsx create mode 100644 .snippets/code/products/queries/guides/use-queries/query-request-with-api-key.jsx create mode 100644 .snippets/code/products/queries/guides/use-queries/test-full.jsx delete mode 100644 products/queries/guides/construct-a-query.md delete mode 100644 products/queries/guides/mock-a-query.md delete mode 100644 products/queries/guides/query-request.md delete mode 100644 products/queries/guides/submit-response.md create mode 100644 products/queries/guides/use-queries.md delete mode 100644 products/queries/guides/verify-response.md diff --git a/.snippets/code/products/queries/guides/use-queries/eth-call-initial-request.txt b/.snippets/code/products/queries/guides/use-queries/eth-call-initial-request.txt new file mode 100644 index 000000000..f9444496f --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/eth-call-initial-request.txt @@ -0,0 +1 @@ +curl https://ethereum.publicnode.com -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","data":"0x18160ddd"},"latest"],"id":1}' \ No newline at end of file diff --git a/.snippets/code/products/queries/guides/use-queries/eth-call-initial-response.txt b/.snippets/code/products/queries/guides/use-queries/eth-call-initial-response.txt new file mode 100644 index 000000000..6884f7e7e --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/eth-call-initial-response.txt @@ -0,0 +1,5 @@ +{ + "jsonrpc":"2.0", + "id":1, + "result":"0x000000000000000000000000000000000000000000029fd3d129b582d7949e71" +} \ No newline at end of file diff --git a/.snippets/code/products/queries/guides/use-queries/query-demo.sol b/.snippets/code/products/queries/guides/use-queries/query-demo.sol new file mode 100644 index 000000000..c893ae629 --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/query-demo.sol @@ -0,0 +1,137 @@ +// contracts/query/QueryDemo.sol +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; +import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; +import "wormhole-solidity-sdk/QueryResponse.sol"; + +error InvalidOwner(); +// @dev for the onlyOwner modifier +error InvalidCaller(); +error InvalidCalldata(); +error InvalidForeignChainID(); +error ObsoleteUpdate(); +error StaleUpdate(); +error UnexpectedResultLength(); +error UnexpectedResultMismatch(); + +/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. +contract QueryDemo is QueryResponse { + using BytesParsing for bytes; + + struct ChainEntry { + uint16 chainID; + address contractAddress; + uint256 counter; + uint256 blockNum; + uint256 blockTime; + } + + address private immutable owner; + uint16 private immutable myChainID; + mapping(uint16 => ChainEntry) private counters; + uint16[] private foreignChainIDs; + + bytes4 public GetMyCounter = bytes4(hex"916d5743"); + + constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { + if (_owner == address(0)) { + revert InvalidOwner(); + } + owner = _owner; + + myChainID = _myChainID; + counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); + } + + // updateRegistration should be used to add the other chains and to set / update contract addresses. + function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { + if (counters[_chainID].chainID == 0) { + foreignChainIDs.push(_chainID); + counters[_chainID].chainID = _chainID; + } + + counters[_chainID].contractAddress = _contractAddress; + } + + // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. + function getMyCounter() public view returns (uint256) { + return counters[myChainID].counter; + } + + // getState() returns this chain's view of all the counters. It is meant to be used in the front end. + function getState() public view returns (ChainEntry[] memory) { + ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); + ret[0] = counters[myChainID]; + uint256 length = foreignChainIDs.length; + + for (uint256 i = 0; i < length;) { + ret[i + 1] = counters[foreignChainIDs[i]]; + unchecked { + ++i; + } + } + + return ret; + } + + // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. + function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { + ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); + uint256 numResponses = r.responses.length; + if (numResponses != foreignChainIDs.length) { + revert UnexpectedResultLength(); + } + + for (uint256 i = 0; i < numResponses;) { + // Create a storage pointer for frequently read and updated data stored on the blockchain + ChainEntry storage chainEntry = counters[r.responses[i].chainId]; + if (chainEntry.chainID != foreignChainIDs[i]) { + revert InvalidForeignChainID(); + } + + EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); + + // Validate that update is not obsolete + validateBlockNum(eqr.blockNum, chainEntry.blockNum); + + // Validate that update is not stale + validateBlockTime(eqr.blockTime, block.timestamp - 300); + + if (eqr.result.length != 1) { + revert UnexpectedResultMismatch(); + } + + // Validate addresses and function signatures + address[] memory validAddresses = new address[](1); + bytes4[] memory validFunctionSignatures = new bytes4[](1); + validAddresses[0] = chainEntry.contractAddress; + validFunctionSignatures[0] = GetMyCounter; + + validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); + + require(eqr.result[0].result.length == 32, "result is not a uint256"); + + chainEntry.blockNum = eqr.blockNum; + chainEntry.blockTime = eqr.blockTime / 1_000_000; + chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); + + unchecked { + ++i; + } + } + + counters[myChainID].blockNum = block.number; + counters[myChainID].blockTime = block.timestamp; + counters[myChainID].counter += 1; + } + + modifier onlyOwner() { + if (owner != msg.sender) { + revert InvalidOwner(); + } + _; + } +} \ No newline at end of file diff --git a/.snippets/code/products/queries/guides/use-queries/query-proxy-query-response.jsx b/.snippets/code/products/queries/guides/use-queries/query-proxy-query-response.jsx new file mode 100644 index 000000000..1a9031af3 --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/query-proxy-query-response.jsx @@ -0,0 +1,4 @@ +const tx = await contract.updateCounters( + `0x${response.data.bytes}`, + signaturesToEvmStruct(response.data.signatures) +); diff --git a/.snippets/code/products/queries/guides/use-queries/query-request-with-api-key.jsx b/.snippets/code/products/queries/guides/use-queries/query-request-with-api-key.jsx new file mode 100644 index 000000000..15fcfe954 --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/query-request-with-api-key.jsx @@ -0,0 +1,9 @@ +const serialized = request.serialize(); +const proxyResponse = + (await axios.post) < + QueryProxyQueryResponse > + (QUERY_URL, + { + bytes: Buffer.from(serialized).toString("hex"), + }, + { headers: { "X-API-Key": YOUR_API_KEY } }); diff --git a/.snippets/code/products/queries/guides/use-queries/test-full.jsx b/.snippets/code/products/queries/guides/use-queries/test-full.jsx new file mode 100644 index 000000000..5ea02e6b3 --- /dev/null +++ b/.snippets/code/products/queries/guides/use-queries/test-full.jsx @@ -0,0 +1,65 @@ +import { + EthCallData, + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryProxyMock, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; + +const rpc = 'https://ethereum.publicnode.com'; +const callData: EthCallData = { + to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; + +(async () => { + const latestBlock: string = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + if (!latestBlock) { + console.error(`❌ Invalid block returned`); + return; + } + console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); + const targetResponse = await axios.post(rpc, { + method: 'eth_call', + params: [callData, latestBlock], + id: 1, + jsonrpc: '2.0', + }); + // console.log(finalizedResponse.data); + if (targetResponse.data.error) { + console.error(`❌ ${targetResponse.data.error.message}`); + } + const targetResult = targetResponse.data?.result; + console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); + // Form the query request + const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); + console.log(JSON.stringify(request, undefined, 2)); + const mock = new QueryProxyMock({ 2: rpc }); + const mockData = await mock.mock(request); + console.log(mockData); + const mockQueryResponse = QueryResponse.from(mockData.bytes); + const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); +})(); \ No newline at end of file diff --git a/.snippets/text/products/queries/queries-timeline.json b/.snippets/text/products/queries/queries-timeline.json index dc42275ae..add29da89 100644 --- a/.snippets/text/products/queries/queries-timeline.json +++ b/.snippets/text/products/queries/queries-timeline.json @@ -5,17 +5,17 @@ "icon": ":fontawesome-solid-1:" }, { - "title": "[Construct a Query](/docs/products/queries/guides/construct-a-query)", + "title": "[Construct a Query](/docs/products/queries/guides/use-queries/#construct-a-query)", "content": "Set up the query configuration.", "icon": ":fontawesome-solid-2:" }, { - "title": "[Make a Query Request](/docs/products/queries/guides/query-request)", + "title": "[Make a Query Request](/docs/products/queries/guides/use-queries/#make-a-query-request)", "content": "Send your query to the Query Server using HTTPS.", "icon": ":fontawesome-solid-3:" }, { - "title": "[Submit a Query Response](/docs/products/queries/guides/submit-response)", + "title": "[Submit a Query Response](/docs/products/queries/guides/use-queries/#submit-a-query-response-on-chain)", "content": "Post the Guardian-signed VAA to your smart contract.", "icon": ":fontawesome-solid-4:" } diff --git a/products/queries/guides/.pages b/products/queries/guides/.pages index de751d6ae..f21f9f42c 100644 --- a/products/queries/guides/.pages +++ b/products/queries/guides/.pages @@ -1,7 +1,3 @@ title: Guides nav: -- 'Construct a Query': construct-a-query.md -- 'Mock a Query': mock-a-query.md -- 'Make a Query Request': query-request.md -- 'Verify a Query Response': verify-response.md -- 'Submit a Query Response': submit-response.md +- 'Use Queries': use-queries.md diff --git a/products/queries/guides/construct-a-query.md b/products/queries/guides/construct-a-query.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/guides/construct-a-query.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/queries/guides/mock-a-query.md b/products/queries/guides/mock-a-query.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/guides/mock-a-query.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/queries/guides/query-request.md b/products/queries/guides/query-request.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/guides/query-request.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/queries/guides/submit-response.md b/products/queries/guides/submit-response.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/guides/submit-response.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/queries/guides/use-queries.md b/products/queries/guides/use-queries.md new file mode 100644 index 000000000..0223edc44 --- /dev/null +++ b/products/queries/guides/use-queries.md @@ -0,0 +1,160 @@ +--- +title: Use Queries +description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. +categories: Queries +--- + +# Use Queries + +You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. + +This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. + +## Construct a Query {: #construct-a-query} + +You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. + +```jsx +npm i @wormhole-foundation/wormhole-query-sdk axios +``` + +In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. + +You can request the latest block from a public node using `eth_getBlockByNumber`. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:12:12' +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:19:26' +``` + +Then construct the call data. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:13:16' +``` + +Finally, put it all together in a `QueryRequest`. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:44:53' +``` + +This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:54:54' + // { + // "nonce": 0, + // "requests": [ + // { + // "chainId": 2, + // "query": { + // "callData": [ + // { + // "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + // "data": "0x18160ddd" + // } + // ], + // "blockTag": "0x11e9068" + // } + // } + // ], + // "version": 1 + // } +``` + +## Mock a Query + +For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:55:57' + // { + // signatures: ['...'], + // bytes: '...' + // } +``` + +This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx:58:64' + // Mock Query Result: + // 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee + // (3172556167631284394053614) +``` + +Testing this all together might look like the following: + +```jsx +--8<-- 'code/products/queries/guides/use-queries/test-full.jsx' +``` + +### Fork Testing + +It is common to test against a local fork of Mainnet with something like + +```jsx +anvil --fork-url https://ethereum.publicnode.com +``` + +In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. + +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. + +```jsx +npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe +``` + +If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. + +## Make a Query Request + +The standardized means of making a `QueryRequest` with an API key is as follows: + +```jsx +--8<-- 'code/products/queries/guides/use-queries/query-request-with-api-key.jsx' +``` + +Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. + +A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` + +A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` + +## Verify a Query Response On-Chain + +A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +Broadly, using a query response on-chain comes down to three main steps: + + 1. Parse and verify the query response + 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract + 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: + - Is the request against the expected chain? + - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing + - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks + - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases + - Is the result of the expected length for the expected result type? + 4. Run `abi.decode` on the result + +See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. + +??? code "View the complete `QueryDemo`" + ```solidity + --8<-- 'code/products/queries/guides/use-queries/query-demo.sol' + ``` + +## Submit a Query Response On-Chain + +The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. + +This example submits the transaction to the demo contract: + +```jsx +--8<-- 'code/products/queries/guides/use-queries/query-proxy-query-response.jsx' +``` \ No newline at end of file diff --git a/products/queries/guides/verify-response.md b/products/queries/guides/verify-response.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/guides/verify-response.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file From 4951ec461991befcbf32721f5c951adb02d97d1c Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Fri, 30 May 2025 16:50:49 +0200 Subject: [PATCH 40/55] Ilariae/todos (#441) * fixed most todo links * add links * Update products/native-token-transfers/guides/deploy-to-solana.md Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- products/cctp-bridge/.pages | 1 - products/cctp-bridge/concepts/.pages | 4 ---- products/cctp-bridge/concepts/integration.md | 1 - products/cctp-bridge/get-started.md | 2 +- products/cctp-bridge/overview.md | 2 +- products/connect/get-started.md | 3 ++- products/connect/overview.md | 6 +++--- products/messaging/get-started.md | 1 - products/messaging/overview.md | 4 ++-- products/multigov/guides/deploy-to-evm.md | 2 +- .../native-token-transfers/guides/deploy-to-evm.md | 4 ++-- .../native-token-transfers/guides/deploy-to-solana.md | 10 +++++----- .../native-token-transfers/guides/evm-launchpad.md | 2 +- products/queries/.pages | 1 - products/queries/concepts/.pages | 3 --- products/queries/concepts/rpc-basics.md | 1 - products/token-bridge/get-started.md | 2 +- 17 files changed, 19 insertions(+), 30 deletions(-) delete mode 100644 products/cctp-bridge/concepts/.pages delete mode 100644 products/cctp-bridge/concepts/integration.md delete mode 100644 products/queries/concepts/.pages delete mode 100644 products/queries/concepts/rpc-basics.md diff --git a/products/cctp-bridge/.pages b/products/cctp-bridge/.pages index d59ff1898..4eeee24e9 100644 --- a/products/cctp-bridge/.pages +++ b/products/cctp-bridge/.pages @@ -4,4 +4,3 @@ nav: - 'Get Started': get-started.md - guides - tutorials -- concepts diff --git a/products/cctp-bridge/concepts/.pages b/products/cctp-bridge/concepts/.pages deleted file mode 100644 index 492548c78..000000000 --- a/products/cctp-bridge/concepts/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Concepts -nav: -- 'Wormhole Integration': integration.md -- 'CCTP Docs': https://developers.circle.com/stablecoins/cctp-getting-started diff --git a/products/cctp-bridge/concepts/integration.md b/products/cctp-bridge/concepts/integration.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/cctp-bridge/concepts/integration.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/cctp-bridge/get-started.md b/products/cctp-bridge/get-started.md index 76efe23ae..c540e6cfd 100644 --- a/products/cctp-bridge/get-started.md +++ b/products/cctp-bridge/get-started.md @@ -85,4 +85,4 @@ To verify the transaction and view its details, paste the transaction hash into Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: - - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features \ No newline at end of file + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started): Learn how USDC cross-chain transfers work and explore advanced CCTP features. \ No newline at end of file diff --git a/products/cctp-bridge/overview.md b/products/cctp-bridge/overview.md index 13c4e48f8..be38edbd0 100644 --- a/products/cctp-bridge/overview.md +++ b/products/cctp-bridge/overview.md @@ -75,5 +75,5 @@ Integrating Wormhole's messaging with CCTP enables the secure transfer of native Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: - [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. -- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Complete USDC Transfer Flow**](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. - [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. \ No newline at end of file diff --git a/products/connect/get-started.md b/products/connect/get-started.md index 343bb527e..82dc6346c 100644 --- a/products/connect/get-started.md +++ b/products/connect/get-started.md @@ -77,9 +77,10 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -Use the following guides to configure your Connect instance: +Use the following guides to configure your Connect instance and integrate it into your application: - **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +- **[Integrate Connect into a React DApp](/docs/products/connect/tutorials/react-dapp/)**: Learn how to integrate Connect into a React application, including setting up the widget and handling transfers. diff --git a/products/connect/overview.md b/products/connect/overview.md index 654db14c6..0c6ca988e 100644 --- a/products/connect/overview.md +++ b/products/connect/overview.md @@ -10,7 +10,7 @@ With the Wormhole Connect widget, you can enable users to perform multichain ass ## Key Features -Wormhole connect's notable features include: +Connect's notable features include: - **In-app multichain transfers**: Bridge assets without leaving your app. - **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. @@ -27,7 +27,7 @@ When a user initiates a multichain transfer, Connect walks them through key step 1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. 2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). 3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. -4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. 5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. 6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. 7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. @@ -41,7 +41,7 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution diff --git a/products/messaging/get-started.md b/products/messaging/get-started.md index f7430d40f..a6149e236 100644 --- a/products/messaging/get-started.md +++ b/products/messaging/get-started.md @@ -97,5 +97,4 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. \ No newline at end of file diff --git a/products/messaging/overview.md b/products/messaging/overview.md index 3bdc53f9e..6e9f92aaa 100644 --- a/products/messaging/overview.md +++ b/products/messaging/overview.md @@ -59,6 +59,6 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. diff --git a/products/multigov/guides/deploy-to-evm.md b/products/multigov/guides/deploy-to-evm.md index ccb809ea8..4bdec947c 100644 --- a/products/multigov/guides/deploy-to-evm.md +++ b/products/multigov/guides/deploy-to-evm.md @@ -6,7 +6,7 @@ categories: MultiGov # Deploy MultiGov on EVM Chains -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/products/multigov/get-started/){target=\_blank}. Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. diff --git a/products/native-token-transfers/guides/deploy-to-evm.md b/products/native-token-transfers/guides/deploy-to-evm.md index c02c531bd..34bbe53ad 100644 --- a/products/native-token-transfers/guides/deploy-to-evm.md +++ b/products/native-token-transfers/guides/deploy-to-evm.md @@ -44,7 +44,7 @@ For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), th This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. -For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. +For more detailed information, see the [Deployment Models](/docs/products/native-token-transfers/overview/#deployment-models){target=\_blank}. ### Key Differences Between Modes @@ -141,4 +141,4 @@ The final step in the deployment process is to set the NTT Manager as a minter o By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. !!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. \ No newline at end of file + To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} page. \ No newline at end of file diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index 69c1371b5..3fdfc204f 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -102,10 +102,10 @@ Deploying NTT with the CLI on Solana follows a structured process: !!! note NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -2. **Choose your [deployment model](TODO){target=\_blank}**: +2. **Choose your deployment model**: - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program 3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode @@ -117,7 +117,7 @@ By default, NTT transfers to Solana require manual [relaying](/docs/protocol/inf To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +The [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: 1. **Create a new NTT project** - set up a deployment workspace @@ -249,7 +249,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + [:custom-arrow: Test Your NTT deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** diff --git a/products/native-token-transfers/guides/evm-launchpad.md b/products/native-token-transfers/guides/evm-launchpad.md index 0e7fedf39..20a4a15f4 100644 --- a/products/native-token-transfers/guides/evm-launchpad.md +++ b/products/native-token-transfers/guides/evm-launchpad.md @@ -164,7 +164,7 @@ This section displays key [roles](/docs/products/native-token-transfers/configur ### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +Determine and update how transceivers interact with the token. [Transceivers](/docs/products/native-token-transfers/concepts/architecture/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. diff --git a/products/queries/.pages b/products/queries/.pages index 1f5a8dafb..c03aa7cbf 100644 --- a/products/queries/.pages +++ b/products/queries/.pages @@ -3,6 +3,5 @@ nav: - 'Overview': overview.md - 'Get Started': get-started.md - guides -- concepts - 'FAQs': faqs.md - reference diff --git a/products/queries/concepts/.pages b/products/queries/concepts/.pages deleted file mode 100644 index c2adbdd18..000000000 --- a/products/queries/concepts/.pages +++ /dev/null @@ -1,3 +0,0 @@ -title: Concepts -nav: -- 'RPC Basics': rpc-basics.md \ No newline at end of file diff --git a/products/queries/concepts/rpc-basics.md b/products/queries/concepts/rpc-basics.md deleted file mode 100644 index 30404ce4c..000000000 --- a/products/queries/concepts/rpc-basics.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/products/token-bridge/get-started.md b/products/token-bridge/get-started.md index 6dd291c91..256e68a62 100644 --- a/products/token-bridge/get-started.md +++ b/products/token-bridge/get-started.md @@ -10,7 +10,7 @@ categories: Token-Bridge, Transfers Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - **Manual transfer** – where you control each step - **Automatic transfer** – where a relayer finalizes the transfer for you From 141366c68d76754575e5ccc83118fd44926f5ca1 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Fri, 30 May 2025 17:00:31 +0200 Subject: [PATCH 41/55] clean up ntt (#438) * clean up ntt * clean up --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- .../guides/install-ntt-project.md | 38 ++++++++++ .../guides/deploy-to-evm.md | 73 +++++++------------ .../guides/deploy-to-solana.md | 35 ++------- products/reference/supported-networks.md | 2 +- 4 files changed, 72 insertions(+), 76 deletions(-) create mode 100644 .snippets/text/products/native-token-transfers/guides/install-ntt-project.md diff --git a/.snippets/text/products/native-token-transfers/guides/install-ntt-project.md b/.snippets/text/products/native-token-transfers/guides/install-ntt-project.md new file mode 100644 index 000000000..b048f4504 --- /dev/null +++ b/.snippets/text/products/native-token-transfers/guides/install-ntt-project.md @@ -0,0 +1,38 @@ +Before proceeding, make sure you have the NTT CLI installed and a project initialized. + +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): + +1. Install the NTT CLI: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + + Verify installation: + + ```bash + ntt --version + ``` + +2. Initialize a new NTT project: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +3. Create the deployment config**: + + === "Mainnet" + + ```bash + ntt init Mainnet + ``` + + === "Testnet" + + ```bash + ntt init Testnet + ``` + + This generates a `deployment.json` file where your deployment settings will be stored. diff --git a/products/native-token-transfers/guides/deploy-to-evm.md b/products/native-token-transfers/guides/deploy-to-evm.md index 34bbe53ad..58b9e9250 100644 --- a/products/native-token-transfers/guides/deploy-to-evm.md +++ b/products/native-token-transfers/guides/deploy-to-evm.md @@ -4,7 +4,11 @@ description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for categories: NTT, Transfer --- -# Native Token Transfers (NTT) EVM Development +# Deploy Native Token Transfers (NTT) to EVM Chains + +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of ERC-20 tokens on [supported EVM-compatible chains](/docs/products/reference/supported-networks/#ntt){target=\_blank} using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. + +This guide walks you through deploying NTT on EVM chains, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. ## Deploy Your Token and Ensure Compatibility @@ -12,67 +16,42 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. - -#### Burn-and-Mint Mode +Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: +??? interface "Burn-and-Mint" -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` + Tokens must implement the following non-standard ERC-20 functions: -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. - -??? code "View the complete `INttToken` Interface`" - ```solidity - --8<-- 'code/products/native-token-transfers/guides/deploy-to-evm/INttToken.sol' - ``` + - `burn(uint256 amount)` + - `mint(address account, uint256 amount)` -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. + These functions aren't part of the standard ERC-20 interface. Refer to the [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} for all required functions, errors, and events. -#### Hub-and-Spoke Mode - -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. - - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers - -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. + ??? interface "`INttToken` Interface" + ```solidity + --8<-- 'code/products/native-token-transfers/guides/deploy-to-evm/INttToken.sol' + ``` -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. + You’ll also need to set mint authority to the relevant `NttManager` contract. Example deployment scripts are available in the [`example-ntt-token` GitHub repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank}. -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. +??? interface "Hub-and-Spoke Mode" -For more detailed information, see the [Deployment Models](/docs/products/native-token-transfers/overview/#deployment-models){target=\_blank}. + Tokens only need to be ERC-20 compliant. The hub chain serves as the source of truth for supply consistency, while only spoke chains need to support minting and burning. For example, if Ethereum is the hub and Polygon is a spoke: -### Key Differences Between Modes + - Tokens are locked on Ethereum + - Tokens are minted or burned on Polygon - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency + This setup maintains a consistent total supply across all chains. ## Deploy NTT -Create a new NTT project: +Before deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration. -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` - -Initialize a new `deployment.json` file specifying the network: - -=== "Testnet" +???- interface "Install the NTT CLI and Scaffold a New Project" + + --8<-- 'text/products/native-token-transfers/guides/install-ntt-project.md' - ```bash - ntt init Testnet - ``` - -=== "Mainnet" - - ```bash - ntt init Mainnet - ``` +Once you've completed those steps, return here to proceed with adding your EVM chains and deploying contracts. Ensure you have set up your environment correctly: diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index 3fdfc204f..faa4530ba 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -8,14 +8,7 @@ categories: NTT, Transfer [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - -The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. - -![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) - -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. - +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. ## Prerequisites @@ -109,6 +102,8 @@ Deploying NTT with the CLI on Solana follows a structured process: 3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. @@ -119,28 +114,12 @@ To integrate your token with NTT on Solana, you must initialize the deployment a The [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: -1. **Create a new NTT project** - set up a deployment workspace +???- interface "Install the NTT CLI and Scaffold a New Project" - ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME - ``` + --8<-- 'text/products/native-token-transfers/guides/install-ntt-project.md' -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings - - === "Mainnet" - - ```bash - ntt init Mainnet - ``` - - === "Testnet" - - ```bash - ntt init Testnet - ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. + !!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. ### Generate an NTT Program Key Pair diff --git a/products/reference/supported-networks.md b/products/reference/supported-networks.md index 2d8a582e3..feef5b767 100644 --- a/products/reference/supported-networks.md +++ b/products/reference/supported-networks.md @@ -8,7 +8,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product --8<-- 'text/build/start-building/supported-networks/connect.md' --8<-- 'text/build/start-building/supported-networks/ntt.md' From 06d7f34dd1364931b2be6790534be71d17c23ba7 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 11:01:56 -0400 Subject: [PATCH 42/55] update llms --- llms-files/llms-basics.txt | 5 +- llms-files/llms-connect.txt | 16 +- llms-files/llms-multigov.txt | 9 +- llms-files/llms-ntt.txt | 157 +-- llms-files/llms-queries.txt | 405 ++++++- llms-files/llms-reference.txt | 2 +- llms-files/llms-relayers.txt | 7 +- llms-files/llms-settlement.txt | 265 ++++- llms-files/llms-solidity-sdk.txt | 7 +- llms-files/llms-token-bridge.txt | 9 +- llms-files/llms-transfer.txt | 428 ++++++-- llms-files/llms-typescript-sdk.txt | 721 +++++-------- llms-full.txt | 1617 ++++++++++++++++++---------- llms.txt | 10 +- 14 files changed, 2455 insertions(+), 1203 deletions(-) diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index eaada8d62..b307b0a06 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -327,7 +327,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -977,8 +976,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index e4ba6c1c6..047a7d0cc 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -979,10 +979,11 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -Use the following guides to configure your Connect instance: +Use the following guides to configure your Connect instance and integrate it into your application: - **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +- **[Integrate Connect into a React DApp](/docs/products/connect/tutorials/react-dapp/)**: Learn how to integrate Connect into a React application, including setting up the widget and handling transfers. --- END CONTENT --- @@ -1646,7 +1647,7 @@ With the Wormhole Connect widget, you can enable users to perform multichain ass ## Key Features -Wormhole connect's notable features include: +Connect's notable features include: - **In-app multichain transfers**: Bridge assets without leaving your app. - **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. @@ -1663,7 +1664,7 @@ When a user initiates a multichain transfer, Connect walks them through key step 1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. 2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). 3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. -4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. 5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. 6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. 7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. @@ -1677,7 +1678,7 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution @@ -2102,7 +2103,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -2752,8 +2752,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -4778,7 +4778,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 527941d23..fed88bb65 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -545,7 +545,7 @@ categories: MultiGov # Deploy MultiGov on EVM Chains -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/products/multigov/get-started/){target=\_blank}. Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. @@ -1349,7 +1349,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -1999,8 +1998,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -4025,7 +4024,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 6d6fc7e5b..069be4b63 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -697,7 +697,11 @@ description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for categories: NTT, Transfer --- -# Native Token Transfers (NTT) EVM Development +# Deploy Native Token Transfers (NTT) to EVM Chains + +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of ERC-20 tokens on [supported EVM-compatible chains](/docs/products/reference/supported-networks/#ntt){target=\_blank} using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. + +This guide walks you through deploying NTT on EVM chains, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. ## Deploy Your Token and Ensure Compatibility @@ -705,20 +709,20 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** -#### Burn-and-Mint Mode +??? interface "Burn-and-Mint" -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: + Tokens must implement the following non-standard ERC-20 functions: -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` + - `burn(uint256 amount)` + - `mint(address account, uint256 amount)` -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. + These functions aren't part of the standard ERC-20 interface. Refer to the [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} for all required functions, errors, and events. -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 + ??? interface "`INttToken` Interface" + ```solidity + // SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; interface INttToken { @@ -754,54 +758,66 @@ interface INttToken { // found in the `ERC20Burnable` interface. function burn(uint256 amount) external; } - ``` - -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - -#### Hub-and-Spoke Mode + ``` -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. + You’ll also need to set mint authority to the relevant `NttManager` contract. Example deployment scripts are available in the [`example-ntt-token` GitHub repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank}. - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers +??? interface "Hub-and-Spoke Mode" -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. + Tokens only need to be ERC-20 compliant. The hub chain serves as the source of truth for supply consistency, while only spoke chains need to support minting and burning. For example, if Ethereum is the hub and Polygon is a spoke: -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. + - Tokens are locked on Ethereum + - Tokens are minted or burned on Polygon -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. + This setup maintains a consistent total supply across all chains. -For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. - -### Key Differences Between Modes +## Deploy NTT - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +Before deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration. -## Deploy NTT +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. -Create a new NTT project: +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` +1. Install the NTT CLI: -Initialize a new `deployment.json` file specifying the network: + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -=== "Testnet" + Verify installation: ```bash - ntt init Testnet + ntt --version ``` -=== "Mainnet" +2. Initialize a new NTT project: ```bash - ntt init Mainnet + ntt new my-ntt-project + cd my-ntt-project ``` +3. Create the deployment config**: + + === "Mainnet" + + ```bash + ntt init Mainnet + ``` + + === "Testnet" + + ```bash + ntt init Testnet + ``` + + This generates a `deployment.json` file where your deployment settings will be stored. + +Once you've completed those steps, return here to proceed with adding your EVM chains and deploying contracts. + Ensure you have set up your environment correctly: ```bash @@ -876,7 +892,7 @@ The final step in the deployment process is to set the NTT Manager as a minter o By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. !!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. + To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} page. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ @@ -891,14 +907,7 @@ categories: NTT, Transfer [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - -The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. - -![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) - -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. - +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. ## Prerequisites @@ -985,13 +994,15 @@ Deploying NTT with the CLI on Solana follows a structured process: !!! note NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -2. **Choose your [deployment model](TODO){target=\_blank}**: +2. **Choose your deployment model**: - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program 3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. @@ -1000,16 +1011,34 @@ By default, NTT transfers to Solana require manual [relaying](/docs/protocol/inf To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +The [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: + +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. + +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): + +1. Install the NTT CLI: -1. **Create a new NTT project** - set up a deployment workspace + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + + Verify installation: + + ```bash + ntt --version + ``` + +2. Initialize a new NTT project: ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME + ntt new my-ntt-project + cd my-ntt-project ``` -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +3. Create the deployment config**: === "Mainnet" @@ -1022,8 +1051,11 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an ```bash ntt init Testnet ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. + + This generates a `deployment.json` file where your deployment settings will be stored. + + !!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. ### Generate an NTT Program Key Pair @@ -1132,7 +1164,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + [:custom-arrow: Test Your NTT deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** @@ -1329,7 +1361,7 @@ This section displays key [roles](/docs/products/native-token-transfers/configur ### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +Determine and update how transceivers interact with the token. [Transceivers](/docs/products/native-token-transfers/concepts/architecture/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. @@ -2281,7 +2313,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -2931,8 +2962,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -4957,7 +4988,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 8422e78a5..a5ceb8c9f 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -15,6 +15,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/use-queries.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md [type: other] @@ -231,6 +232,403 @@ Now that you've successfully run your first verifiable query, you are ready to g Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/queries/guides/use-queries/ +--- BEGIN CONTENT --- +--- +title: Use Queries +description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. +categories: Queries +--- + +# Use Queries + +You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. + +This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. + +## Construct a Query {: #construct-a-query} + +You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. + +```jsx +npm i @wormhole-foundation/wormhole-query-sdk axios +``` + +In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. + +You can request the latest block from a public node using `eth_getBlockByNumber`. + +```jsx + +await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; +``` + +Then construct the call data. + +```jsx +to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; +``` + +Finally, put it all together in a `QueryRequest`. + +```jsx +const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); +``` + +This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. + +```jsx + + // { + // "nonce": 0, + // "requests": [ + // { + // "chainId": 2, + // "query": { + // "callData": [ + // { + // "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + // "data": "0x18160ddd" + // } + // ], + // "blockTag": "0x11e9068" + // } + // } + // ], + // "version": 1 + // } +``` + +## Mock a Query + +For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. + +```jsx +const mockData = await mock.mock(request); + console.log(mockData); + // { + // signatures: ['...'], + // bytes: '...' + // } +``` + +This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. + +```jsx +const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); + // Mock Query Result: + // 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee + // (3172556167631284394053614) +``` + +Testing this all together might look like the following: + +```jsx +import { + EthCallData, + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryProxyMock, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; + +const rpc = 'https://ethereum.publicnode.com'; +const callData: EthCallData = { + to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; + +(async () => { + const latestBlock: string = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + if (!latestBlock) { + console.error(`❌ Invalid block returned`); + return; + } + console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); + const targetResponse = await axios.post(rpc, { + method: 'eth_call', + params: [callData, latestBlock], + id: 1, + jsonrpc: '2.0', + }); + // console.log(finalizedResponse.data); + if (targetResponse.data.error) { + console.error(`❌ ${targetResponse.data.error.message}`); + } + const targetResult = targetResponse.data?.result; + console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); + // Form the query request + const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); + console.log(JSON.stringify(request, undefined, 2)); + const mock = new QueryProxyMock({ 2: rpc }); + const mockData = await mock.mock(request); + console.log(mockData); + const mockQueryResponse = QueryResponse.from(mockData.bytes); + const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); +})(); +``` + +### Fork Testing + +It is common to test against a local fork of Mainnet with something like + +```jsx +anvil --fork-url https://ethereum.publicnode.com +``` + +In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. + +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. + +```jsx +npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe +``` + +If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. + +## Make a Query Request + +The standardized means of making a `QueryRequest` with an API key is as follows: + +```jsx +const serialized = request.serialize(); +const proxyResponse = + (await axios.post) < + QueryProxyQueryResponse > + (QUERY_URL, + { + bytes: Buffer.from(serialized).toString("hex"), + }, + { headers: { "X-API-Key": YOUR_API_KEY } }); +``` + +Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. + +A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` + +A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` + +## Verify a Query Response On-Chain + +A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +Broadly, using a query response on-chain comes down to three main steps: + + 1. Parse and verify the query response + 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract + 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: + - Is the request against the expected chain? + - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing + - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks + - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases + - Is the result of the expected length for the expected result type? + 4. Run `abi.decode` on the result + +See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. + +??? code "View the complete `QueryDemo`" + ```solidity + // contracts/query/QueryDemo.sol +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; +import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; +import "wormhole-solidity-sdk/QueryResponse.sol"; + +error InvalidOwner(); +// @dev for the onlyOwner modifier +error InvalidCaller(); +error InvalidCalldata(); +error InvalidForeignChainID(); +error ObsoleteUpdate(); +error StaleUpdate(); +error UnexpectedResultLength(); +error UnexpectedResultMismatch(); + +/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. +contract QueryDemo is QueryResponse { + using BytesParsing for bytes; + + struct ChainEntry { + uint16 chainID; + address contractAddress; + uint256 counter; + uint256 blockNum; + uint256 blockTime; + } + + address private immutable owner; + uint16 private immutable myChainID; + mapping(uint16 => ChainEntry) private counters; + uint16[] private foreignChainIDs; + + bytes4 public GetMyCounter = bytes4(hex"916d5743"); + + constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { + if (_owner == address(0)) { + revert InvalidOwner(); + } + owner = _owner; + + myChainID = _myChainID; + counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); + } + + // updateRegistration should be used to add the other chains and to set / update contract addresses. + function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { + if (counters[_chainID].chainID == 0) { + foreignChainIDs.push(_chainID); + counters[_chainID].chainID = _chainID; + } + + counters[_chainID].contractAddress = _contractAddress; + } + + // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. + function getMyCounter() public view returns (uint256) { + return counters[myChainID].counter; + } + + // getState() returns this chain's view of all the counters. It is meant to be used in the front end. + function getState() public view returns (ChainEntry[] memory) { + ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); + ret[0] = counters[myChainID]; + uint256 length = foreignChainIDs.length; + + for (uint256 i = 0; i < length;) { + ret[i + 1] = counters[foreignChainIDs[i]]; + unchecked { + ++i; + } + } + + return ret; + } + + // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. + function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { + ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); + uint256 numResponses = r.responses.length; + if (numResponses != foreignChainIDs.length) { + revert UnexpectedResultLength(); + } + + for (uint256 i = 0; i < numResponses;) { + // Create a storage pointer for frequently read and updated data stored on the blockchain + ChainEntry storage chainEntry = counters[r.responses[i].chainId]; + if (chainEntry.chainID != foreignChainIDs[i]) { + revert InvalidForeignChainID(); + } + + EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); + + // Validate that update is not obsolete + validateBlockNum(eqr.blockNum, chainEntry.blockNum); + + // Validate that update is not stale + validateBlockTime(eqr.blockTime, block.timestamp - 300); + + if (eqr.result.length != 1) { + revert UnexpectedResultMismatch(); + } + + // Validate addresses and function signatures + address[] memory validAddresses = new address[](1); + bytes4[] memory validFunctionSignatures = new bytes4[](1); + validAddresses[0] = chainEntry.contractAddress; + validFunctionSignatures[0] = GetMyCounter; + + validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); + + require(eqr.result[0].result.length == 32, "result is not a uint256"); + + chainEntry.blockNum = eqr.blockNum; + chainEntry.blockTime = eqr.blockTime / 1_000_000; + chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); + + unchecked { + ++i; + } + } + + counters[myChainID].blockNum = block.number; + counters[myChainID].blockTime = block.timestamp; + counters[myChainID].counter += 1; + } + + modifier onlyOwner() { + if (owner != msg.sender) { + revert InvalidOwner(); + } + _; + } +} + ``` + +## Submit a Query Response On-Chain + +The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. + +This example submits the transaction to the demo contract: + +```jsx +const tx = await contract.updateCounters( + `0x${response.data.bytes}`, + signaturesToEvmStruct(response.data.signatures) +); +``` +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/queries/overview/ --- BEGIN CONTENT --- --- @@ -719,7 +1117,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -1369,8 +1766,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -3395,7 +3792,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 66111fdd8..88bb8d780 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -551,7 +551,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 9cc3b7850..faa637851 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -868,7 +868,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -1518,8 +1517,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -3544,7 +3543,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 86da80493..78b9c4996 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -15,6 +15,7 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] @@ -153,6 +154,263 @@ After the user receives the token upfront, the execution of additional contract If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started +description: Perform a cross-chain token swap using Wormhole Settlement and the Mayan Swift route with the TypeScript SDK on mainnet. +categories: Settlement, Transfer +--- + +# Get Started + +[Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. + +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. + +By the end, you'll have a working script that: + +- Resolves token transfer routes using Mayan Swift +- Quotes and validates the best route +- Initiates a swap on a source chain and completes the transfer on a destination chain + +!!! note + Mayan Swift currently supports **mainnet only**. Attempting to run this demo on a testnet will fail. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#settlement){target=\_blank} + +This example uses Ethereum as the source chain and Solana as the destination. As a result, you'll need an Ethereum wallet with ETH for gas and a Solana wallet with SOL for fees. You can adapt the example to match your preferred chains. + +## Set Up a Project + +Start by scaffolding a basic Node.js project and installing the required SDKs. + +1. Create a new project folder: + + ```bash + mkdir settlement-swap + cd settlement-swap + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk-connect \ + @wormhole-foundation/sdk-evm \ + @wormhole-foundation/sdk-solana \ + @mayanfinance/wormhole-sdk-route \ + dotenv + npm install -D typescript tsx + ``` + +3. Create the file structure: + + ```bash + mkdir src + touch src/helpers.ts src/swap.ts .env .gitignore + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `MAINNET_ETH_PRIVATE_KEY` and `MAINNET_SOL_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [cast wallet](https://book.getfoundry.sh/reference/cast/cast-wallet/){target=_blank}. + + !!! warning + If you use a .env file during development, add it to your .gitignore to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Swap + +This section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source and destination chain signers. + +Then, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and completes the transfer on Solana. + +1. Open `helper.ts` and define the `getSigner` utility function to load private keys, instantiate signers for Ethereum and Solana, and return the signers along with the Wormhole-formatted address: + + ```ts title="src/helpers.ts" + import { + Chain, + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, +} from '@wormhole-foundation/sdk-connect'; +import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm'; +import { getSolanaSigner } from '@wormhole-foundation/sdk-solana'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (MAINNET_ETH_PRIVATE_KEY, MAINNET_SOL_PRIVATE_KEY) + * must be loaded securely beforehand, for example via a keystore, + * secrets manager, or environment variables (not recommended). + */ +// Define Transfer Interface +export interface SignerContext { + signer: Signer; + address: ChainAddress; +} + +export async function getSigner( + chain: ChainContext +): Promise> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + switch (platform) { + case 'Solana': + signer = await getSolanaSigner( + await chain.getRpc(), + getEnv('MAINNET_SOL_PRIVATE_KEY') + ); + break; + case 'Evm': + signer = await getEvmSignerForKey( + await chain.getRpc(), + getEnv('MAINNET_ETH_PRIVATE_KEY') + ); + break; + default: + throw new Error('Unrecognized platform: ' + platform); + } + + return { + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `swap.ts`, add the following script, which will handle all of the logic required to perform the token swap: + + ```ts title="src/swap.ts" + import { Wormhole, routes } from '@wormhole-foundation/sdk-connect'; +import { EvmPlatform } from '@wormhole-foundation/sdk-evm'; +import { SolanaPlatform } from '@wormhole-foundation/sdk-solana'; +import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route'; +import { getSigner } from './helpers'; + +(async function () { + // Setup + const wh = new Wormhole('Mainnet', [EvmPlatform, SolanaPlatform]); + + const sendChain = wh.getChain('Ethereum'); + const destChain = wh.getChain('Solana'); + + // To transfer native ETH on Ethereum to native SOL on Solana + const source = Wormhole.tokenId(sendChain.chain, 'native'); + const destination = Wormhole.tokenId(destChain.chain, 'native'); + + // Create a new Wormhole route resolver, adding the Mayan route to the default list + // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type, + // but MayanRouteSWIFT is compatible and works as intended in this context. + const resolver = wh.resolver([MayanRouteSWIFT]); + + // Show supported tokens + const dstTokens = await resolver.supportedDestinationTokens( + source, + sendChain, + destChain + ); + console.log(dstTokens.slice(0, 5)); + + // Load signers and addresses from helpers + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); + + // Creating a transfer request fetches token details + // since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source, + destination, + }); + + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + const bestRoute = foundRoutes[0]!; + + // Specify the amount as a decimal string + const transferParams = { + amount: '0.002', + options: bestRoute.getDefaultOptions(), + }; + + // Validate the queries route + let validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) { + console.error(validated.error); + return; + } + console.log('Validated: ', validated); + + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) { + console.error(`Error fetching a quote: ${quote.error.message}`); + return; + } + console.log('Quote: ', quote); + + // Initiate the transfer + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); + + await routes.checkAndCompleteTransfer( + bestRoute, + receipt, + receiver.signer, + 15 * 60 * 1000 + ); +})(); + ``` + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx src/swap.ts + ``` + + If successful, you’ll see terminal output like this: + +
    +npx tsx src/swap.ts +Validated: { valid: true, ... } +Quote: { success: true, ... } +Initiated transfer with receipt: ... +Checking transfer state... +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: DestinationFinalized + +
    + +Congratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement. + +## Customize the Integration + +You can tailor the example to your use case by adjusting: + +- **Tokens and chains**: Use `getSupportedTokens()` to explore what's available. +- **Source and destination chains**: Modify `sendChain` and `destChain` in `swap.ts`. +- **Transfer settings**: Update the amount or route parameters. +- **Signer management**: Modify `src/helpers.ts` to integrate with your preferred wallet setup. + +## Next Steps + +Once you've chosen a path, follow the corresponding guide to start building: + +- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. + +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- @@ -930,7 +1188,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -1580,8 +1837,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -3606,7 +3863,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index bc6c04e27..32c3a0201 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -1921,7 +1921,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -2571,8 +2570,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -4597,7 +4596,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index ca62305b8..be85045fb 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -559,7 +559,7 @@ categories: Token-Bridge, Transfers Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - **Manual transfer** – where you control each step - **Automatic transfer** – where a relayer finalizes the transfer for you @@ -1459,7 +1459,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -2109,8 +2108,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -4135,7 +4134,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index 1d06d751f..25dfee8e2 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -43,6 +43,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] @@ -453,7 +454,7 @@ To verify the transaction and view its details, paste the transaction hash into Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: - - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started): Learn how USDC cross-chain transfers work and explore advanced CCTP features. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/cctp-contracts/ @@ -3159,7 +3160,7 @@ Integrating Wormhole's messaging with CCTP enables the secure transfer of native Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: - [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. -- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Complete USDC Transfer Flow**](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. - [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. --- END CONTENT --- @@ -3931,10 +3932,11 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -Use the following guides to configure your Connect instance: +Use the following guides to configure your Connect instance and integrate it into your application: - **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +- **[Integrate Connect into a React DApp](/docs/products/connect/tutorials/react-dapp/)**: Learn how to integrate Connect into a React application, including setting up the widget and handling transfers. --- END CONTENT --- @@ -4598,7 +4600,7 @@ With the Wormhole Connect widget, you can enable users to perform multichain ass ## Key Features -Wormhole connect's notable features include: +Connect's notable features include: - **In-app multichain transfers**: Bridge assets without leaving your app. - **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. @@ -4615,7 +4617,7 @@ When a user initiates a multichain transfer, Connect walks them through key step 1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. 2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). 3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. -4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. 5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. 6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. 7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. @@ -4629,7 +4631,7 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution @@ -5404,7 +5406,11 @@ description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for categories: NTT, Transfer --- -# Native Token Transfers (NTT) EVM Development +# Deploy Native Token Transfers (NTT) to EVM Chains + +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of ERC-20 tokens on [supported EVM-compatible chains](/docs/products/reference/supported-networks/#ntt){target=\_blank} using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. + +This guide walks you through deploying NTT on EVM chains, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. ## Deploy Your Token and Ensure Compatibility @@ -5412,20 +5418,20 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** -#### Burn-and-Mint Mode +??? interface "Burn-and-Mint" -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: + Tokens must implement the following non-standard ERC-20 functions: -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` + - `burn(uint256 amount)` + - `mint(address account, uint256 amount)` -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. + These functions aren't part of the standard ERC-20 interface. Refer to the [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} for all required functions, errors, and events. -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 + ??? interface "`INttToken` Interface" + ```solidity + // SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; interface INttToken { @@ -5461,54 +5467,66 @@ interface INttToken { // found in the `ERC20Burnable` interface. function burn(uint256 amount) external; } - ``` - -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - -#### Hub-and-Spoke Mode - -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. + ``` - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers + You’ll also need to set mint authority to the relevant `NttManager` contract. Example deployment scripts are available in the [`example-ntt-token` GitHub repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank}. -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +??? interface "Hub-and-Spoke Mode" -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. + Tokens only need to be ERC-20 compliant. The hub chain serves as the source of truth for supply consistency, while only spoke chains need to support minting and burning. For example, if Ethereum is the hub and Polygon is a spoke: -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. + - Tokens are locked on Ethereum + - Tokens are minted or burned on Polygon -For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. + This setup maintains a consistent total supply across all chains. -### Key Differences Between Modes +## Deploy NTT - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +Before deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration. -## Deploy NTT +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. -Create a new NTT project: +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` +1. Install the NTT CLI: -Initialize a new `deployment.json` file specifying the network: + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -=== "Testnet" + Verify installation: ```bash - ntt init Testnet + ntt --version ``` -=== "Mainnet" +2. Initialize a new NTT project: ```bash - ntt init Mainnet + ntt new my-ntt-project + cd my-ntt-project ``` +3. Create the deployment config**: + + === "Mainnet" + + ```bash + ntt init Mainnet + ``` + + === "Testnet" + + ```bash + ntt init Testnet + ``` + + This generates a `deployment.json` file where your deployment settings will be stored. + +Once you've completed those steps, return here to proceed with adding your EVM chains and deploying contracts. + Ensure you have set up your environment correctly: ```bash @@ -5583,7 +5601,7 @@ The final step in the deployment process is to set the NTT Manager as a minter o By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. !!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. + To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} page. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ @@ -5598,14 +5616,7 @@ categories: NTT, Transfer [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - -The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. - -![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) - -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. - +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. ## Prerequisites @@ -5692,13 +5703,15 @@ Deploying NTT with the CLI on Solana follows a structured process: !!! note NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -2. **Choose your [deployment model](TODO){target=\_blank}**: +2. **Choose your deployment model**: - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program 3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. @@ -5707,16 +5720,34 @@ By default, NTT transfers to Solana require manual [relaying](/docs/protocol/inf To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +The [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: -1. **Create a new NTT project** - set up a deployment workspace +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. + +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): + +1. Install the NTT CLI: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + + Verify installation: ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME + ntt --version ``` -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +2. Initialize a new NTT project: + + ```bash + ntt new my-ntt-project + cd my-ntt-project + ``` + +3. Create the deployment config**: === "Mainnet" @@ -5729,8 +5760,11 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an ```bash ntt init Testnet ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. + + This generates a `deployment.json` file where your deployment settings will be stored. + + !!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. ### Generate an NTT Program Key Pair @@ -5839,7 +5873,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + [:custom-arrow: Test Your NTT deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** @@ -6036,7 +6070,7 @@ This section displays key [roles](/docs/products/native-token-transfers/configur ### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +Determine and update how transceivers interact with the token. [Transceivers](/docs/products/native-token-transfers/concepts/architecture/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. @@ -6871,6 +6905,263 @@ After the user receives the token upfront, the execution of additional contract If the slippage tolerance is set too low, the user may receive USDC on the destination chain instead of the intended swap outcome. However, the four basis points (bps) fee is non-refundable, as the service provided by Liquidity Layer (LL) solvers (ensuring front-finality) is separate from the composing protocol's services, such as swaps or deposits. --- END CONTENT --- +Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ +--- BEGIN CONTENT --- +--- +title: Get Started +description: Perform a cross-chain token swap using Wormhole Settlement and the Mayan Swift route with the TypeScript SDK on mainnet. +categories: Settlement, Transfer +--- + +# Get Started + +[Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. + +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. + +By the end, you'll have a working script that: + +- Resolves token transfer routes using Mayan Swift +- Quotes and validates the best route +- Initiates a swap on a source chain and completes the transfer on a destination chain + +!!! note + Mayan Swift currently supports **mainnet only**. Attempting to run this demo on a testnet will fail. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#settlement){target=\_blank} + +This example uses Ethereum as the source chain and Solana as the destination. As a result, you'll need an Ethereum wallet with ETH for gas and a Solana wallet with SOL for fees. You can adapt the example to match your preferred chains. + +## Set Up a Project + +Start by scaffolding a basic Node.js project and installing the required SDKs. + +1. Create a new project folder: + + ```bash + mkdir settlement-swap + cd settlement-swap + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk-connect \ + @wormhole-foundation/sdk-evm \ + @wormhole-foundation/sdk-solana \ + @mayanfinance/wormhole-sdk-route \ + dotenv + npm install -D typescript tsx + ``` + +3. Create the file structure: + + ```bash + mkdir src + touch src/helpers.ts src/swap.ts .env .gitignore + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `MAINNET_ETH_PRIVATE_KEY` and `MAINNET_SOL_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [cast wallet](https://book.getfoundry.sh/reference/cast/cast-wallet/){target=_blank}. + + !!! warning + If you use a .env file during development, add it to your .gitignore to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Swap + +This section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source and destination chain signers. + +Then, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and completes the transfer on Solana. + +1. Open `helper.ts` and define the `getSigner` utility function to load private keys, instantiate signers for Ethereum and Solana, and return the signers along with the Wormhole-formatted address: + + ```ts title="src/helpers.ts" + import { + Chain, + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, +} from '@wormhole-foundation/sdk-connect'; +import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm'; +import { getSolanaSigner } from '@wormhole-foundation/sdk-solana'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (MAINNET_ETH_PRIVATE_KEY, MAINNET_SOL_PRIVATE_KEY) + * must be loaded securely beforehand, for example via a keystore, + * secrets manager, or environment variables (not recommended). + */ +// Define Transfer Interface +export interface SignerContext { + signer: Signer; + address: ChainAddress; +} + +export async function getSigner( + chain: ChainContext +): Promise> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + switch (platform) { + case 'Solana': + signer = await getSolanaSigner( + await chain.getRpc(), + getEnv('MAINNET_SOL_PRIVATE_KEY') + ); + break; + case 'Evm': + signer = await getEvmSignerForKey( + await chain.getRpc(), + getEnv('MAINNET_ETH_PRIVATE_KEY') + ); + break; + default: + throw new Error('Unrecognized platform: ' + platform); + } + + return { + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `swap.ts`, add the following script, which will handle all of the logic required to perform the token swap: + + ```ts title="src/swap.ts" + import { Wormhole, routes } from '@wormhole-foundation/sdk-connect'; +import { EvmPlatform } from '@wormhole-foundation/sdk-evm'; +import { SolanaPlatform } from '@wormhole-foundation/sdk-solana'; +import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route'; +import { getSigner } from './helpers'; + +(async function () { + // Setup + const wh = new Wormhole('Mainnet', [EvmPlatform, SolanaPlatform]); + + const sendChain = wh.getChain('Ethereum'); + const destChain = wh.getChain('Solana'); + + // To transfer native ETH on Ethereum to native SOL on Solana + const source = Wormhole.tokenId(sendChain.chain, 'native'); + const destination = Wormhole.tokenId(destChain.chain, 'native'); + + // Create a new Wormhole route resolver, adding the Mayan route to the default list + // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type, + // but MayanRouteSWIFT is compatible and works as intended in this context. + const resolver = wh.resolver([MayanRouteSWIFT]); + + // Show supported tokens + const dstTokens = await resolver.supportedDestinationTokens( + source, + sendChain, + destChain + ); + console.log(dstTokens.slice(0, 5)); + + // Load signers and addresses from helpers + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); + + // Creating a transfer request fetches token details + // since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source, + destination, + }); + + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + const bestRoute = foundRoutes[0]!; + + // Specify the amount as a decimal string + const transferParams = { + amount: '0.002', + options: bestRoute.getDefaultOptions(), + }; + + // Validate the queries route + let validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) { + console.error(validated.error); + return; + } + console.log('Validated: ', validated); + + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) { + console.error(`Error fetching a quote: ${quote.error.message}`); + return; + } + console.log('Quote: ', quote); + + // Initiate the transfer + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); + + await routes.checkAndCompleteTransfer( + bestRoute, + receipt, + receiver.signer, + 15 * 60 * 1000 + ); +})(); + ``` + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx src/swap.ts + ``` + + If successful, you’ll see terminal output like this: + +
    +npx tsx src/swap.ts +Validated: { valid: true, ... } +Quote: { success: true, ... } +Initiated transfer with receipt: ... +Checking transfer state... +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: DestinationFinalized + +
    + +Congratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement. + +## Customize the Integration + +You can tailor the example to your use case by adjusting: + +- **Tokens and chains**: Use `getSupportedTokens()` to explore what's available. +- **Source and destination chains**: Modify `sendChain` and `destChain` in `swap.ts`. +- **Transfer settings**: Update the amount or route parameters. +- **Signer management**: Modify `src/helpers.ts` to integrate with your preferred wallet setup. + +## Next Steps + +Once you've chosen a path, follow the corresponding guide to start building: + +- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. + +--- END CONTENT --- + Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ --- BEGIN CONTENT --- --- @@ -8194,7 +8485,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -8844,8 +9134,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -10870,7 +11160,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 275a381ab..180ad8af8 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -328,7 +328,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -1236,55 +1235,6 @@ This guide helps you install the SDK, initialize a `Wormhole` instance to suppor If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). -## Prerequisites - -Before you begin, make sure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed - -??? example "Project setup instructions" - - Use the following commands to create a TypeScript project: - - 1. Create a directory and initialize a Node.js project: - - ```bash - mkdir wh-ts-demo - cd wh-ts-demo - npm init -y - ``` - - 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: - - ```bash - npm install --save-dev tsx typescript @types/node - ``` - - 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: - - ```bash - npx tsc --init - ``` - - Make sure your `tsconfig.json` includes the following settings: - - ```json - { - "compilerOptions": { - // es2020 or newer - "target": "es2020", - // Use esnext if you configured your package.json with type: "module" - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } - } - ``` - ## Install the SDK To install the Wormhole TypeScript SDK, use the following command: @@ -1354,19 +1304,176 @@ npm install @wormhole-foundation/sdk-evm ## Initialize the SDK -You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. +Getting your integration started is simple. First, import Wormhole: -1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: +```ts +import { wormhole } from '@wormhole-foundation/sdk'; - ```bash - mkdir src - touch src/main.ts - ``` +import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; +import algorand from '@wormhole-foundation/sdk/algorand'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helpers/index.js'; -2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: +(async function () { + const wh = await wormhole('Testnet', [ + evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); - ```ts title="src/main.ts" - import { wormhole } from '@wormhole-foundation/sdk'; + const ctx = wh.getChain('Solana'); + + const rcv = wh.getChain('Algorand'); + + const sender = await getSigner(ctx); + const receiver = await getSigner(rcv); + + // Get a Token Bridge contract client on the source + const sndTb = await ctx.getTokenBridge(); + + // Send the native token of the source chain + const tokenId = Wormhole.tokenId(ctx.chain, 'native'); + + // Bigint amount using `amount` module + const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); + + // Create a transaction stream for transfers + const transfer = sndTb.transfer( + sender.address.address, + receiver.address, + tokenId.address, + amt + ); + + // Sign and send the transaction + const txids = await signSendWait(ctx, transfer, sender.signer); + console.log('Sent: ', txids); + + // Get the Wormhole message ID from the transaction + const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); + console.log('Wormhole Messages: ', whm); + + const vaa = await wh.getVaa( + // Wormhole Message ID + whm!, + // Protocol:Payload name to use for decoding the VAA payload + 'TokenBridge:Transfer', + // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available + 60_000 + ); + + // Now get the token bridge on the redeem side + const rcvTb = await rcv.getTokenBridge(); + + // Create a transaction stream for redeeming + const redeem = rcvTb.redeem(receiver.address.address, vaa!); + + // Sign and send the transaction + const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); + console.log('Sent: ', rcvTxids); + + // Now check if the transfer is completed according to + // the destination token bridge + const finished = await rcvTb.isTransferCompleted(vaa!); + console.log('Transfer completed: ', finished); +})(); +``` + +Then, import each of the ecosystem [platforms](/docs/tools/typescript-sdk/sdk-reference/#platforms) that you wish to support: + +```ts +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +``` + +To make the [platform](/docs/tools/typescript-sdk/sdk-reference/#platforms) modules available for use, pass them to the Wormhole constructor and specify the network (`Mainnet`, `Testnet`, or `Devnet`) you want to interact with: + +```ts +evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); +``` + +With a configured `Wormhole` object, you can begin to interact with these chains. + +## Example Usage + +Follow these steps to confirm that the SDK is initialized correctly and can fetch basic chain information for your target chains. + +### Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript, `tsx` (for running TypeScript files), Node.js type definitions, the base Wormhole SDK, and the platform-specific packages for the chains you want to interact with: + + ```bash + npm install --save-dev tsx typescript @types/node @wormhole-foundation/sdk @wormhole-foundation/sdk-evm @wormhole-foundation/sdk-solana + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + + 4. Initialize the main `Wormhole` class to use the SDK. Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + + 5. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; // Import specific platform modules for the chains you intend to use import evm from '@wormhole-foundation/sdk/evm'; import solana from '@wormhole-foundation/sdk/solana'; @@ -1387,11 +1494,9 @@ main().catch((e) => { console.error('Error initializing Wormhole SDK', e); process.exit(1); }); - ``` - -## Fetch Chain Information + ``` -Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. +### Fetch Chain Information 1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: @@ -2623,14 +2728,9 @@ description: Explore Wormhole's TypeScript SDK and learn how to perform differen categories: Typescript-SDK --- -# Wormhole TypeScript SDK - -## Introduction - -The Wormhole TypeScript SDK is useful for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole. This package bundles together functions, definitions, and constants that streamline the process of connecting chains and completing transfers using Wormhole. The SDK also offers targeted sub-packages for Wormhole-connected platforms, which allow you to add multichain support without creating outsized dependencies. - -This section covers all you need to know about the functionality and ease of development offered through the Wormhole TypeScript SDK. Take a tour of the package to discover how it helps make integration easier. Learn more about how the SDK abstracts away complexities around concepts like platforms, contexts, and signers. Finally, you'll find guidance on usage, along with code examples, to show you how to use the tools of the SDK. +# Wormhole TypeScript SDK Reference +This page covers all you need to know about the functionality offered through the Wormhole TypeScript SDK.
    @@ -2638,350 +2738,70 @@ This section covers all you need to know about the functionality and ease of dev --- - Find installation instructions for both the meta package and installing specific, individual packages + Find installation instructions for both the meta package and installing specific, individual packages. - [:custom-arrow: Install the SDK](#installation) + [:custom-arrow: Install the SDK](/docs/tools/typescript-sdk/get-started/#install-the-sdk) -- :octicons-book-16:{ .lg .middle } **Concepts** - - --- - - Understand key concepts and how the SDK abstracts them away. Learn more about platforms, chain context, addresses, and signers - - [:custom-arrow: Explore concepts](#concepts) - -- :octicons-file-code-16:{ .lg .middle } **Usage** +- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** --- - Guidance on using the SDK to add seamless interchain messaging to your application, including code examples + Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at available methods, classes, interfaces, and definitions. - [:custom-arrow: Use the SDK](#usage) + [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} -- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** +- :octicons-code-square-16:{ .lg .middle } **Source Code** --- - Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at availabel methods, classes, interfaces, and definitions - - [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} + Want to go straight to the source? Check out the TypeScript SDK GitHub repository. + + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/){target=\_blank}
    !!! warning - This package is a work in progress. The interface may change, and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} any issues you find. - -## Installation - -### Basic - -To install the meta package using npm, run the following command in the root directory of your project: - -```bash -npm install @wormhole-foundation/sdk -``` - -This package combines all the individual packages to make setup easier while allowing for tree shaking. - -### Advanced - -Alternatively, you can install a specific set of published packages individually: - -??? interface "`sdk-base` - exposes constants" - - ```sh - npm install @wormhole-foundation/sdk-base - ``` - -??? interface "`sdk-definitions` - exposes contract interfaces, basic types, and VAA payload definitions" - - ```sh - npm install @wormhole-foundation/sdk-definitions - ``` - -??? interface "`sdk-evm` - exposes EVM-specific utilities" - - ```sh - npm install @wormhole-foundation/sdk-evm - ``` - -??? interface "`sdk-evm-tokenbridge` - exposes the EVM Token Bridge protocol client" - - ```sh - npm install @wormhole-foundation/sdk-evm-tokenbridge - ``` - -## Usage - -Getting your integration started is simple. First, import Wormhole: - -```ts -import { wormhole } from '@wormhole-foundation/sdk'; - -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; - -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); - - const ctx = wh.getChain('Solana'); - - const rcv = wh.getChain('Algorand'); - - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); - - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); - - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); - - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); - - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); - - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); - - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); - - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); - - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); - - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); - - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); - - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); -``` - -Then, import each of the ecosystem [platforms](#platforms) that you wish to support: - -```ts -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -``` - - -To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: - -```ts -evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); -``` - -With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. - -```ts - -``` - -You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. - -```ts -// Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); -``` - -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; - -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; - -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); - - const ctx = wh.getChain('Solana'); - - const rcv = wh.getChain('Algorand'); - - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); - - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); - - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); - - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); - - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); - - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); - - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); - - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); - - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); - - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); - - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); - - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); - ``` - -Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. - -```ts -const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, -}); -``` - -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -(async function () { - const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, - }); - console.log(wh.config.chains.Solana); -})(); - ``` + This package is a work in progress. The interface may change, and there are likely bugs. Please [report any issues](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} you find. ## Concepts -Understanding several higher-level Wormhole concepts and how the SDK abstracts them away will help you use the tools most effectively. The following sections will introduce and discuss the concepts of platforms, chain contexts, addresses, signers, and protocols, how they are used in the Wormhole context, and how the SDK helps ease development in each conceptual area. +Understanding key Wormhole concepts—and how the SDK abstracts them—will help you use the tools more effectively. The following sections cover platforms, chain contexts, addresses, signers, and protocols, explaining their roles in Wormhole and how the SDK simplifies working with them. ### Platforms -While every chain has unique attributes, chains from the same platform typically have standard functionalities they share. The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: +The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: -- Protocols, such as [Wormhole core](#wormhole-core), preconfigured to suit the selected platform +- [Protocols](#protocols) preconfigured to suit the selected platform - Definitions and configurations for types, signers, addresses, and chains - Helpers configured for dealing with unsigned transactions on the selected platform -These modules also import and expose essential functions and define types or constants from the chain's native ecosystem to reduce the dependencies needed to interact with a chain using Wormhole. Rather than installing the entire native package for each desired platform, you can install a targeted package of standardized functions and definitions essential to connecting with Wormhole, keeping project dependencies as slim as possible. +These modules expose key functions and types from the native ecosystem, reducing the need for full packages and keeping dependencies lightweight. +??? interface "Supported platform modules" -Wormhole currently supports the following platforms: + | Platform | Installation Command | + |----------|----------------------------------------------------| + | EVM |
    ```@wormhole-foundation/sdk-evm```
    | + | Solana |
    ```@wormhole-foundation/sdk-solana```
    | + | Algorand |
    ```@wormhole-foundation/sdk-algorand```
    | + | Aptos |
    ```@wormhole-foundation/sdk-aptos```
    | + | Cosmos |
    ```@wormhole-foundation/sdk-cosmwasm```
    | + | Sui |
    ```@wormhole-foundation/sdk-sui```
    | -- EVM -- Solana -- Cosmos -- Sui -- Aptos -- Algorand - -See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. + See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. ### Chain Context -The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. +`ChainContext` (from the `@wormhole-foundation/sdk-definitions` package) provides a unified interface for interacting with connected chains. It: + +- Holds network, chain, and platform configurations +- Caches RPC and protocol clients +- Exposes both platform-inherited and chain-specific methods +- Defines the core types used across the SDK: `Network`, `Chain`, and `Platform` ```ts +// Get the chain context for the source and destination chains +// This is useful to grab direct clients for the protocols const srcChain = wh.getChain(senderAddress.chain); const dstChain = wh.getChain(receiverAddress.chain); @@ -2991,7 +2811,7 @@ srcChain.getRpcClient(); // => RpcClient<'Evm'> ### Addresses -The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. +The SDK uses the `UniversalAddress` class to implement the `Address` interface, standardizing address handling across chains. All addresses are parsed into a 32-byte format. Each platform also defines a `NativeAddress` type that understands its native format. These abstractions ensure consistent cross-chain address handling. ```ts // It's possible to convert a string address to its Native address @@ -3017,27 +2837,23 @@ const emitterAddr = ethAddr.toUniversalAddress().toString(); ### Tokens -Similar to the `ChainAddress` type, the `TokenId` type provides the chain and address of a given token. The following snippet introduces `TokenId`, a way to uniquely identify any token, whether it's a standard token or a blockchain's native currency (like ETH for Ethereum). - -Wormhole uses their contract address to create a `TokenId` for standard tokens. For native currencies, Wormhole uses the keyword `native` instead of an address. This makes it easy to work with any type of token consistently. - -Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. +The `TokenId` type identifies any token by its chain and address. For standardized tokens, Wormhole uses the token's contract address. For native currencies (e.g., ETH on Ethereum), it uses the keyword `native`. This ensures consistent handling of all tokens. ```ts +// Get the TokenId for an ERC-20 token const sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...'); - +// Get the TokenId for native ETH const gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native'); - +// Convert a TokenId back to a string const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' ``` ### Signers -Certain methods of signing transactions require a `Signer` interface in the SDK. Depending on the specific requirements, this interface can be fulfilled by either a `SignOnlySigner` or a `SignAndSendSigner`. A signer can be created by wrapping an offline or web wallet. - -A `SignOnlySigner` is used when the signer isn't connected to the network or prefers not to broadcast transactions themselves. It accepts an array of unsigned transactions and returns an array of signed and serialized transactions. Before signing, the transactions may be inspected or altered. It's important to note that the serialization process is chain-specific. Refer to the testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank} or [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for an example of how to implement a signer for a specific chain or platform. +The SDK's `Signer` interface can be implemented as either a `SignOnlySigner` or a `SignAndSendSigner`, created by wrapping an offline or web wallet: -Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. +- **`SignOnlySigner`**: Signs and serializes unsigned transactions without broadcasting them. Transactions can be inspected or modified before signing. Serialization is chain-specific. See testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank}, [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for implementation examples. +- **`SignAndSendSigner`**: Signs and broadcasts transactions, returning their transaction IDs in order. ```ts export type Signer = SignOnlySigner | SignAndSendSigner; @@ -3064,7 +2880,7 @@ export interface SignAndSendSigner { #### Set Up a Signer with Ethers.js -To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: +To sign transactions programmatically with the Wormhole SDK, you can use [Ethers.js](https://docs.ethers.org/){target=\_blank} to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: ```javascript import { ethers } from 'ethers'; @@ -3093,47 +2909,63 @@ async function sendTransaction() { sendTransaction(); ``` - - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions - - - **`signer`** - represents the account that will sign the transaction. In this case, you’re creating a signer using the private key associated with the account. The signer is responsible for authorizing transactions by digitally signing them with the private key - - - **`Wallet`** - combines both the provider (for blockchain interaction) and the signer (for transaction authorization), allowing you to sign and send transactions programmatically +These components work together to create, sign, and submit a transaction to the blockchain: -These components work together to create, sign, and submit a transaction to the blockchain. - -???- tip "Managing Private Keys Securely" - Handling private keys is unavoidable, so it’s crucial to manage them securely. Here are some best practices: - - - **Use environment variables** - avoid hardcoding private keys in your code. Use environment variables or secret management tools to inject private keys securely - - **Hardware wallets** - for production environments, consider integrating hardware wallets to keep private keys secure while allowing programmatic access through the SDK +- **`provider`**: Connects to the Ethereum or EVM-compatible network, enabling data access and transaction submission. +- **`signer`** : Represents the account that signs transactions using a private key. +- **`Wallet`**: Combines provider and signer to create, sign, and send transactions programmatically. ### Protocols -While Wormhole is a Generic Message Passing (GMP) protocol, several protocols have been built to provide specific functionality. If available, each protocol will have a platform-specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain. - -#### Wormhole Core +Wormhole is a Generic Message Passing (GMP) protocol with several specialized protocols built on top. Each protocol has platform-specific implementations providing methods to generate transactions or read on-chain state. + +??? interface "Supported protocol modules" + + | Protocol | Installation Command | + |-----------------------|----------------------------------------------------------------| + | EVM Core |
    ```@wormhole-foundation/sdk-evm-core```
    | + | EVM Token Bridge |
    ```@wormhole-foundation/sdk-evm-tokenbridge```
    | + | EVM CCTP |
    ```@wormhole-foundation/sdk-evm-cctp```
    | + | EVM Portico |
    ```@wormhole-foundation/sdk-evm-portico```
    | + | EVM TBTC |
    ```@wormhole-foundation/sdk-evm-tbtc```
    | + | Solana Core |
    ```@wormhole-foundation/sdk-solana-core```
    | + | Solana Token Bridge |
    ```@wormhole-foundation/sdk-solana-tokenbridge```
    | + | Solana CCTP |
    ```@wormhole-foundation/sdk-solana-cctp```
    | + | Solana TBTC |
    ```@wormhole-foundation/sdk-solana-tbtc```
    | + | Algorand Core |
    ```@wormhole-foundation/sdk-algorand-core```
    | + | Algorand Token Bridge |
    ```@wormhole-foundation/sdk-algorand-tokenbridge```
    | + | Aptos Core |
    ```@wormhole-foundation/sdk-aptos-core```
    | + | Aptos Token Bridge |
    ```@wormhole-foundation/sdk-aptos-tokenbridge```
    | + | Aptos CCTP |
    ```@wormhole-foundation/sdk-aptos-cctp```
    | + | Cosmos Core |
    ```@wormhole-foundation/sdk-cosmwasm-core```
    | + | Cosmos Token Bridge |
    ```@wormhole-foundation/sdk-cosmwasm-tokenbridge```
    | + | Sui Core |
    ```@wormhole-foundation/sdk-sui-core```
    | + | Sui Token Bridge |
    ```@wormhole-foundation/sdk-sui-tokenbridge```
    | + | Sui CCTP |
    ```@wormhole-foundation/sdk-sui-cctp```
    | -The core protocol underlies all Wormhole activity. This protocol is responsible for emitting the message containing the information necessary to perform bridging, including the [emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter){target=\_blank}, the [sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence){target=\_blank} for the message, and the payload of the message itself. -The following example demonstrates sending and verifying a message using the Wormhole Core protocol on Solana. - -First, initialize a Wormhole instance for the Testnet environment, specifically for the Solana chain. Then, obtain a signer and its associated address, which will be used to sign transactions. +#### Wormhole Core -Next, get a reference to the core messaging bridge, which is the main interface for interacting with Wormhole's cross-chain messaging capabilities. -The code then prepares a message for publication. This message includes: +The core protocol powers all Wormhole activity by emitting messages containing the [emitter address](/docs/products/reference/glossary/#emitter){target=\_blank}, sequence number, and payload needed for bridging. -- The sender's address -- The message payload (in this case, the encoded string `lol`) -- A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +Example workflow on Solana Testnet: -After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. +1. Initialize a Wormhole instance for Solana. +2. Obtain a signer and its address. +3. Access the core messaging bridge for cross-chain messaging. +4. Prepare a message with: -The code then waits for the Wormhole network to process and sign the message, turning it into a Verified Action Approval (VAA). This VAA is retrieved in a `Uint8Array` format, with a timeout of 60 seconds. + - Sender's address + - Encoded payload (e.g., "lol") + - Nonce (e.g., 0) + - Consistency level (e.g., 0) -Lastly, the code will demonstrate how to verify the message on the receiving end. A verification transaction is prepared using the original sender's address and the VAA, and finally, this transaction is signed and sent. +5. Generate, sign, and send the transaction to publish the message. +6. Extract the Wormhole message ID from transaction logs for tracking. +7. Wait (up to 60s) to receive the [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} (in `Uint8Array` format) from the Wormhole network. +8. Prepare and send a verification transaction on the receiving chain using the sender's address and the VAA. -???+ code "View the complete script" +???+ example "Example workflow" ```ts import { encoding, signSendWait, wormhole } from '@wormhole-foundation/sdk'; import { getSigner } from './helpers/index.js'; @@ -3188,7 +3020,7 @@ The payload contains the information necessary to perform whatever action is req #### Token Bridge -The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. +The most familiar protocol built on Wormhole is the Token Bridge. Each supported chain has a `TokenBridge` client that provides a consistent interface for transferring tokens and handling attestations. While `WormholeTransfer` abstractions are recommended, direct interaction with the protocol is also supported. ```ts import { signSendWait } from '@wormhole-foundation/sdk'; @@ -3200,8 +3032,6 @@ const txGenerator = tb.createAttestation(token); const txids = await signSendWait(srcChain, txGenerator, src.signer); ``` -Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. - ## Transfers While using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens. @@ -3210,17 +3040,15 @@ The `WormholeTransfer` interface provides a convenient abstraction to encapsulat ### Token Transfers -Performing a token transfer is trivial for any source and destination chains. You can create a new `Wormhole` object to make objects like `TokenTransfer` and `CircleTransfer`, to transfer tokens between chains. - -The following example demonstrates the process of initiating and completing a token transfer. It starts by creating a `TokenTransfer` object, which tracks the transfer's state throughout its lifecycle. The code then obtains a quote for the transfer, ensuring the amount is sufficient to cover fees and any requested native gas. +Token transfers between chains are straightforward using Wormhole. Create a `Wormhole` instance and use it to initialize a `TokenTransfer` or `CircleTransfer` object. -The transfer process is divided into three main steps: +The example below shows how to initiate and complete a `TokenTransfer`. After creating the transfer object and retrieving a quote (to verify sufficient amount and fees), the process involves: -1. Initiating the transfer on the source chain -2. Waiting for the transfer to be attested (if not automatic) -3. Completing the transfer on the destination chain +1. Initiating the transfer on the source chain. +2. Waiting for attestation (if required). +3. Completing the transfer on the destination chain. -For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. +For automatic transfers, the process ends after initiation. Manual transfers require attestation before completion. ```ts const xfer = await wh.tokenTransfer( @@ -3439,17 +3267,15 @@ async function tokenTransfer(
    ``` -Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. +Internally, this uses the [`TokenBridge`](#token-bridge) protocol client to transfer tokens. ### Native USDC Transfers -You can also transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. Please note that if the transfer is set to `Automatic` mode, a fee for performing the relay will be included in the quote. This fee is deducted from the total amount requested to be sent. For example, if the user wishes to receive `1.0` on the destination, the amount sent should be adjusted to `1.0` plus the relay fee. The same principle applies to native gas drop offs. +You can transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. If the transfer is set to `automatic`, the quote will include a relay fee, which is deducted from the total amount sent. For example, to receive 1.0 USDC on the destination chain, the sender must cover both the 1.0 and the relay fee. The same applies when including a native gas drop-off. -In the following example, the `wh.circleTransfer` function is called with several parameters to set up the transfer. It takes the amount to be transferred (in the token's base units), the sender's chain and address, and the receiver's chain and address. The function also allows specifying whether the transfer should be automatic, meaning it will be completed without further user intervention. +In the example below, the `wh.circleTransfer` function is used to initiate the transfer. It accepts the amount (in base units), sender and receiver chains and addresses, and an optional automatic flag to enable hands-free completion. You can also include an optional payload (set to `undefined` here) and specify a native gas drop-off if desired. -An optional payload can be included with the transfer, though it's set to undefined in this case. Finally, if the transfer is automatic, you can request that native gas (the blockchain's native currency used for transaction fees) be sent to the receiver along with the transferred tokens. - -When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. +When waiting for the VAA, a timeout of `60,000` milliseconds is used. The actual wait time [varies by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. ```ts // Amount as bigint (base units) @@ -3833,11 +3659,9 @@ Once the tokens are selected, a `RouteTransferRequest` may be created to provide ); ``` -Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - -After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. +Choosing the best route is up to the developer and may involve sorting by output amount or estimated completion time (though no estimate is currently provided). -After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. +Once a route is selected, parameters like `amount`, `nativeGasDropoff`, and `slippage` can be set. After validation, a transfer quote is requested, including fees, estimated time, and final amount. If successful, the quote is shown to the user for review before proceeding, ensuring all details are verified prior to transfer. ```ts 'This route offers the following default options', @@ -4338,7 +4162,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -4988,8 +4811,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/products/ @@ -7014,7 +6837,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product diff --git a/llms-full.txt b/llms-full.txt index 05fecb0bf..ef311a970 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -7,7 +7,6 @@ Documentation: https://wormhole.com/docs/ ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/cctp-contracts.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md @@ -54,14 +53,9 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/construct-a-query.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/mock-a-query.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/query-request.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md +Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/use-queries.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md @@ -145,11 +139,6 @@ Each category file includes foundational content from the **Basics** and **Refer The `llms-full.txt` file may exceed the input limits of some language models due to its size. If you encounter limitations, consider using the files by category. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/cctp-bridge/concepts/integration/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/cctp-bridge/get-started/ --- BEGIN CONTENT --- --- @@ -365,7 +354,7 @@ To verify the transaction and view its details, paste the transaction hash into Now that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration: - - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank} – learn how USDC cross-chain transfers work and explore advanced CCTP features + - [**Circle CCTP Documentation**](https://developers.circle.com/stablecoins/cctp-getting-started): Learn how USDC cross-chain transfers work and explore advanced CCTP features. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/cctp-bridge/guides/cctp-contracts/ @@ -3071,7 +3060,7 @@ Integrating Wormhole's messaging with CCTP enables the secure transfer of native Now that you're familiar with CCTP, here is a list of resources for more hands-on practice: - [**Get started with CCTP Bridge**](/docs/products/cctp-bridge/get-started/): Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP. -- [**Complete USDC Transfer Flow**](Todo): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. +- [**Complete USDC Transfer Flow**](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/): Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery. - [**Checkout Circle's CCTP Docs**](https://developers.circle.com/stablecoins/cctp-getting-started){target=\_blank}: Learn more about Circle's cross-chain transfer protocol in their documentation. --- END CONTENT --- @@ -5095,10 +5084,11 @@ Congratulations! You've successfully used Connect to create a simple multichain ## Next Steps -Use the following guides to configure your Connect instance: +Use the following guides to configure your Connect instance and integrate it into your application: - **[Data Configuration](/docs/products/connect/configuration/data/)**: Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more. - **[Theme Configuration](/docs/products/connect/configuration/theme/)**: Learn how to customize Connect's look and feel to match your application's branding. +- **[Integrate Connect into a React DApp](/docs/products/connect/tutorials/react-dapp/)**: Learn how to integrate Connect into a React application, including setting up the widget and handling transfers. --- END CONTENT --- @@ -5762,7 +5752,7 @@ With the Wormhole Connect widget, you can enable users to perform multichain ass ## Key Features -Wormhole connect's notable features include: +Connect's notable features include: - **In-app multichain transfers**: Bridge assets without leaving your app. - **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\_blank} such as Token Bridge, CCTP, or NTT. @@ -5779,7 +5769,7 @@ When a user initiates a multichain transfer, Connect walks them through key step 1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer. 2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic). 3. **Transaction submission on source chain**: Confirms the transfer details to trigger the asset lock or deposit on the initial blockchain. Connect will guide you through the transaction process. -4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} or CCTP attestation. +4. **VAA or attestation creation**: Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the source transaction and produce a [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank}. 5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain. 6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA. 7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet. @@ -5793,7 +5783,7 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/) – handles user-friendly asset transfers + - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution @@ -6389,7 +6379,6 @@ Congratulations! You've published your first multichain message using Wormhole's ## Next Steps - [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/){target=\_blank}: Follow this guide to start working with multichain token transfers using Wormhole Token Bridge's lock and mint mechanism to send tokens across chains. - - [**Get Started with the Solidity SDK**](/docs/tools/solidity-sdk/get-started/){target=\_blank}: Smart contract developers can follow this on-chain integration guide to use Wormhole Solidity SDK-based sender and receiver contracts to send testnet USDC across chains. --- END CONTENT --- @@ -7039,8 +7028,8 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co Follow these steps to work with Wormhole Messaging: -- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank} - use the core protocol to publish a multichain message and return transaction info with VAA identifiers -- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank} - send and receive messages without off-chain infrastructure +- [**Get Started with Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Use the core protocol to publish a multichain message and return transaction info with VAA identifiers. +- [**Use Wormhole Relayers**](/docs/products/messaging/guides/wormhole-relayers/){target=\_blank}: Send and receive messages without off-chain infrastructure. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/messaging/tutorials/cross-chain-contracts/ @@ -10983,7 +10972,7 @@ categories: MultiGov # Deploy MultiGov on EVM Chains -This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](TODO){target=\_blank}. +This guide provodes instructions to set up and deploy the MultiGov governance system locally. Before diving into the technical deployment, ensure that MultiGov is the right fit for your project’s governance needs by following the steps for the [integration process](/docs/products/multigov/get-started/){target=\_blank}. Once your project is approved through the intake process and you’ve collaborated with the Tally team to tailor MultiGov to your requirements, use this guide to configure, compile, and deploy the necessary smart contracts across your desired blockchain networks. This deployment will enable decentralized governance across your hub and spoke chains. @@ -12354,7 +12343,11 @@ description: Deploy and configure Wormhole’s Native Token Transfers (NTT) for categories: NTT, Transfer --- -# Native Token Transfers (NTT) EVM Development +# Deploy Native Token Transfers (NTT) to EVM Chains + +[Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of ERC-20 tokens on [supported EVM-compatible chains](/docs/products/reference/supported-networks/#ntt){target=\_blank} using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. + +This guide walks you through deploying NTT on EVM chains, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. ## Deploy Your Token and Ensure Compatibility @@ -12362,20 +12355,20 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT is an open framework that supports various deployment modes. The NTT CLI currently supports two deployment modes: burn-and-mint and hub-and-spoke. These modes differ in how tokens are managed across chains. +Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** -#### Burn-and-Mint Mode +??? interface "Burn-and-Mint" -Tokens integrated with `NttManager` in `burning` mode require the following two functions to be present: + Tokens must implement the following non-standard ERC-20 functions: -- `burn(uint256 amount)` -- `mint(address account, uint256 amount)` + - `burn(uint256 amount)` + - `mint(address account, uint256 amount)` -These functions aren't part of the standard ERC-20 interface. The [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} documents the required functions and convenience methods, errors, and events. + These functions aren't part of the standard ERC-20 interface. Refer to the [`INttToken` interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/INttToken.sol){target=\_blank} for all required functions, errors, and events. -??? code "View the complete `INttToken` Interface`" - ```solidity - // SPDX-License-Identifier: Apache 2 + ??? interface "`INttToken` Interface" + ```solidity + // SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; interface INttToken { @@ -12411,54 +12404,66 @@ interface INttToken { // found in the `ERC20Burnable` interface. function burn(uint256 amount) external; } - ``` - -Later, you set mint authority to the corresponding `NttManager` contract. You can also follow the scripts in the [example NTT token](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank} repository to deploy a token contract. - -#### Hub-and-Spoke Mode - -A central hub chain (e.g., Ethereum) manages the total token supply in hub-and-spoke mode. Other chains (spokes) mint or burn tokens during cross-chain transfers, ensuring consistency with the locked tokens on the hub chain. + ``` - - **Hub chain** - tokens are locked on the hub chain when transferring to spoke chains - - **Spoke chains** - tokens are native to the spoke chains and are either minted or burned during cross-chain transfers + You’ll also need to set mint authority to the relevant `NttManager` contract. Example deployment scripts are available in the [`example-ntt-token` GitHub repository](https://github.com/wormhole-foundation/example-ntt-token){target=\_blank}. -!!! note - The only requirement for using the NTT framework is an ERC20 token, which can be newly deployed or existing. Steps like setting mint authority apply only to spoke chains. +??? interface "Hub-and-Spoke Mode" -For example, when transferring tokens from Ethereum (hub) to Polygon (spoke), the NTT Manager locks tokens on Ethereum, and the corresponding amount is minted on Polygon. Similarly, transferring tokens back from Polygon to Ethereum burns the tokens on Polygon and unlocks the equivalent tokens on Ethereum. + Tokens only need to be ERC-20 compliant. The hub chain serves as the source of truth for supply consistency, while only spoke chains need to support minting and burning. For example, if Ethereum is the hub and Polygon is a spoke: -This process ensures that the total token supply remains consistent across all chains, with the hub chain acting as the source of truth. + - Tokens are locked on Ethereum + - Tokens are minted or burned on Polygon -For more detailed information, see the [Deployment Models](TODO){target=\_blank} page. + This setup maintains a consistent total supply across all chains. -### Key Differences Between Modes +## Deploy NTT - - **Burn-and-mint** - tokens must implement custom `mint` and `burn` functions, allowing each chain to manage token issuance independently - - **Hub-and-spoke** - tokens only need to be ERC20 compliant, with the hub chain acting as the source of truth for supply consistency +Before deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration. -## Deploy NTT +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. -Create a new NTT project: +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): -```bash -ntt new my-ntt-deployment -cd my-ntt-deployment -``` +1. Install the NTT CLI: -Initialize a new `deployment.json` file specifying the network: + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` -=== "Testnet" + Verify installation: ```bash - ntt init Testnet + ntt --version ``` -=== "Mainnet" +2. Initialize a new NTT project: ```bash - ntt init Mainnet + ntt new my-ntt-project + cd my-ntt-project ``` +3. Create the deployment config**: + + === "Mainnet" + + ```bash + ntt init Mainnet + ``` + + === "Testnet" + + ```bash + ntt init Testnet + ``` + + This generates a `deployment.json` file where your deployment settings will be stored. + +Once you've completed those steps, return here to proceed with adding your EVM chains and deploying contracts. + Ensure you have set up your environment correctly: ```bash @@ -12533,7 +12538,7 @@ The final step in the deployment process is to set the NTT Manager as a minter o By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer. !!!important - To proceed with testing and find integration examples, check out the [NTT Post Deployment](TODO){target=\_blank} page. + To proceed with testing and find integration examples, check out the [NTT Post Deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} page. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-solana/ @@ -12548,14 +12553,7 @@ categories: NTT, Transfer [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} enable seamless multichain transfers of SPL tokens on Solana using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties. -This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. - -The diagram below shows a high-level view of the Solana NTT deployment flow. It illustrates the full lifecycle, from token setup to selecting the transfer mode and configuring and deploying the NTT program using the CLI. This visual is a quick reference for how each step connects in the Solana deployment process. - -![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) - -By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. - +This guide walks you through deploying NTT on Solana, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode. By the end, a fully deployed NTT will be set up, allowing your token to transfer between Solana and other supported chains. ## Prerequisites @@ -12642,13 +12640,15 @@ Deploying NTT with the CLI on Solana follows a structured process: !!! note NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://spl.solana.com/transfer-hook-interface){target=\_blank}. -2. **Choose your [deployment model](TODO){target=\_blank}**: +2. **Choose your deployment model**: - - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required - - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program + - **Hub-and-spoke** - tokens are locked on a hub chain and minted on destination spoke chains. Since the token supply remains controlled by the hub chain, no changes to the minting authority are required + - **Burn-and-mint** - tokens are burned on the source chain and minted on the destination chain. This requires transferring the SPL token's minting authority to the Program Derived Address (PDA) controlled by the NTT program 3. **Deploy and configure NTT** - use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode +![Solana NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp) + Following this process, your token will fully integrate with NTT, enabling seamless transfers between Solana and other chains. By default, NTT transfers to Solana require manual [relaying](/docs/protocol/infrastructure/relayer/){target=\_blank}, meaning users must complete a transaction on Solana to finalize the transfer. For automatic relaying, where transactions are completed without user intervention, additional setup is required. [Contact Wormhole contributors](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\_blank} to enable automatic relaying support for your deployment. @@ -12657,16 +12657,34 @@ By default, NTT transfers to Solana require manual [relaying](/docs/protocol/inf To integrate your token with NTT on Solana, you must initialize the deployment and configure its parameters. This process sets up the required contracts and may generate key pairs if they don't exist. These key pairs are used to sign transactions and authorize actions within the NTT deployment. -The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: +The [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} manages deployments, configures settings, and interacts with the NTT system. Follow these steps to set up NTT using the CLI tool: + +???- interface "Install the NTT CLI and Scaffold a New Project" + + Before proceeding, make sure you have the NTT CLI installed and a project initialized. + +Follow these steps (or see the [Get Started guide](/docs/products/native-token-transfers/get-started/#install-ntt-cli){target=\_blank}): + +1. Install the NTT CLI: + + ```bash + curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash + ``` + + Verify installation: + + ```bash + ntt --version + ``` -1. **Create a new NTT project** - set up a deployment workspace +2. Initialize a new NTT project: ```bash - ntt new INSERT_PROJECT_NAME - cd INSERT_PROJECT_NAME + ntt new my-ntt-project + cd my-ntt-project ``` -2. **Initialize the deployment** - generate a `deployment.json` file with your deployment settings +3. Create the deployment config**: === "Mainnet" @@ -12679,8 +12697,11 @@ The [NTT CLI](TODO){target=\_blank} manages deployments, configures settings, an ```bash ntt init Testnet ``` -!!! note - Testnet deployment settings work for both Solana Testnet and Devnet networks. + + This generates a `deployment.json` file where your deployment settings will be stored. + + !!! note + Testnet deployment settings work for both Solana Testnet and Devnet networks. ### Generate an NTT Program Key Pair @@ -12789,7 +12810,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Follow the NTT Post Deployment Guide for integration examples and testing instructions. - [:custom-arrow: Test Your NTT deployment](TODO){target=\_blank} + [:custom-arrow: Test Your NTT deployment](/docs/products/native-token-transfers/guides/post-deployment/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Add NTT to Your dApp** @@ -12986,7 +13007,7 @@ This section displays key [roles](/docs/products/native-token-transfers/configur ### Security Threshold -Determine and update how transceivers interact with the token. [Transceivers](TODO){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. +Determine and update how transceivers interact with the token. [Transceivers](/docs/products/native-token-transfers/concepts/architecture/#transceivers){target=\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks. A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. @@ -13689,11 +13710,6 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data [**MultiGov**](/docs/products/multigov/overview/){target=\_blank} is a unified governance framework that manages multichain protocol governance through a single mechanism. Best for projects managing multichain governance and protocol updates. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/queries/concepts/rpc-basics/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/queries/faqs/ --- BEGIN CONTENT --- --- @@ -13904,29 +13920,401 @@ Now that you've successfully run your first verifiable query, you are ready to g Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/queries/guides/construct-a-query/ +Doc-Content: https://wormhole.com/docs/products/queries/guides/use-queries/ --- BEGIN CONTENT --- -TODO ---- END CONTENT --- +--- +title: Use Queries +description: Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. +categories: Queries +--- -Doc-Content: https://wormhole.com/docs/products/queries/guides/mock-a-query/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +# Use Queries -Doc-Content: https://wormhole.com/docs/products/queries/guides/query-request/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +You can visit the [Example Queries Demo](https://wormholelabs-xyz.github.io/example-queries-demo/){target=\_blank} to view an interactive example of an application interacting with the [Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract. -Doc-Content: https://wormhole.com/docs/products/queries/guides/submit-response/ ---- BEGIN CONTENT --- -TODO ---- END CONTENT --- +This guide covers using a simple `eth_call` request to get the total supply of WETH on Ethereum. -Doc-Content: https://wormhole.com/docs/products/queries/guides/verify-response/ ---- BEGIN CONTENT --- -TODO +## Construct a Query {: #construct-a-query} + +You can use the [Wormhole Query SDK](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} to construct a query. You will also need an RPC endpoint from the provider of your choice. This example uses [Axios](https://www.npmjs.com/package/axios){target=\_blank} for RPC requests. Ensure that you also have [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed. + +```jsx +npm i @wormhole-foundation/wormhole-query-sdk axios +``` + +In order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request. + +You can request the latest block from a public node using `eth_getBlockByNumber`. + +```jsx + +await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; +``` + +Then construct the call data. + +```jsx +to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; +``` + +Finally, put it all together in a `QueryRequest`. + +```jsx +const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); +``` + +This request consists of one `PerChainQueryRequest`, which is an `EthCallQueryRequest` to Ethereum. You can use `console.log` to print the JSON object and review the structure. + +```jsx + + // { + // "nonce": 0, + // "requests": [ + // { + // "chainId": 2, + // "query": { + // "callData": [ + // { + // "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + // "data": "0x18160ddd" + // } + // ], + // "blockTag": "0x11e9068" + // } + // } + // ], + // "version": 1 + // } +``` + +## Mock a Query + +For easier testing, the Query SDK provides a `QueryProxyMock` method. This method will perform the request and sign the result with the [Devnet](https://github.com/wormhole-foundation/wormhole/blob/main/DEVELOP.md){target=\_blank} Guardian key. The `mock` call returns the same format as the Query Proxy. + +```jsx +const mockData = await mock.mock(request); + console.log(mockData); + // { + // signatures: ['...'], + // bytes: '...' + // } +``` + +This response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client. + +```jsx +const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); + // Mock Query Result: + // 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee + // (3172556167631284394053614) +``` + +Testing this all together might look like the following: + +```jsx +import { + EthCallData, + EthCallQueryRequest, + EthCallQueryResponse, + PerChainQueryRequest, + QueryProxyMock, + QueryRequest, + QueryResponse, +} from '@wormhole-foundation/wormhole-query-sdk'; +import axios from 'axios'; + +const rpc = 'https://ethereum.publicnode.com'; +const callData: EthCallData = { + to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH + data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature("totalSupply()") +}; + +(async () => { + const latestBlock: string = ( + await axios.post(rpc, { + method: 'eth_getBlockByNumber', + params: ['latest', false], + id: 1, + jsonrpc: '2.0', + }) + ).data?.result?.number; + if (!latestBlock) { + console.error(`❌ Invalid block returned`); + return; + } + console.log('Latest Block: ', latestBlock, `(${BigInt(latestBlock)})`); + const targetResponse = await axios.post(rpc, { + method: 'eth_call', + params: [callData, latestBlock], + id: 1, + jsonrpc: '2.0', + }); + // console.log(finalizedResponse.data); + if (targetResponse.data.error) { + console.error(`❌ ${targetResponse.data.error.message}`); + } + const targetResult = targetResponse.data?.result; + console.log('Target Result: ', targetResult, `(${BigInt(targetResult)})`); + // Form the query request + const request = new QueryRequest( + 0, // Nonce + [ + new PerChainQueryRequest( + 2, // Ethereum Wormhole Chain ID + new EthCallQueryRequest(latestBlock, [callData]) + ), + ] + ); + console.log(JSON.stringify(request, undefined, 2)); + const mock = new QueryProxyMock({ 2: rpc }); + const mockData = await mock.mock(request); + console.log(mockData); + const mockQueryResponse = QueryResponse.from(mockData.bytes); + const mockQueryResult = ( + mockQueryResponse.responses[0].response as EthCallQueryResponse + ).results[0]; + console.log( + `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})` + ); +})(); +``` + +### Fork Testing + +It is common to test against a local fork of Mainnet with something like + +```jsx +anvil --fork-url https://ethereum.publicnode.com +``` + +In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. + +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. + +```jsx +npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe +``` + +If you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://book.getfoundry.sh/anvil/){target=\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://book.getfoundry.sh/reference/anvil/#mining-modes){target=\_blank} with the `-b` flag if you want to test code that waits naturally for the chain to advance. For integration tests, you may want to simply `anvil_mine` with `0x20`. + +## Make a Query Request + +The standardized means of making a `QueryRequest` with an API key is as follows: + +```jsx +const serialized = request.serialize(); +const proxyResponse = + (await axios.post) < + QueryProxyQueryResponse > + (QUERY_URL, + { + bytes: Buffer.from(serialized).toString("hex"), + }, + { headers: { "X-API-Key": YOUR_API_KEY } }); +``` + +Remember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`. + +A Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query` + +A Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query` + +## Verify a Query Response On-Chain + +A [`QueryResponseLib` library](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/QueryResponse.sol){target=\_blank} is provided to assist with verifying query responses. You can begin by installing the [Wormhole Solidity SDK](https://github.com/wormhole-foundation/wormhole-solidity-sdk){target=\_blank} with the following command: + +```bash +forge install wormhole-foundation/wormhole-solidity-sdk +``` + +Broadly, using a query response on-chain comes down to three main steps: + + 1. Parse and verify the query response + 2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract + 3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following: + - Is the request against the expected chain? + - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing + - Is the resulting block number and time expected? Some consumers might require that a block number be higher than the last, or the block time be within the last 5 minutes. `validateBlockNum` and `validateBlockTime` can help with the checks + - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases + - Is the result of the expected length for the expected result type? + 4. Run `abi.decode` on the result + +See the [QueryDemo](https://github.com/wormholelabs-xyz/example-queries-demo/blob/main/src/QueryDemo.sol){target=\_blank} contract for an example and read the docstrings of the preceding methods for detailed usage instructions. + +??? code "View the complete `QueryDemo`" + ```solidity + // contracts/query/QueryDemo.sol +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; +import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; +import "wormhole-solidity-sdk/QueryResponse.sol"; + +error InvalidOwner(); +// @dev for the onlyOwner modifier +error InvalidCaller(); +error InvalidCalldata(); +error InvalidForeignChainID(); +error ObsoleteUpdate(); +error StaleUpdate(); +error UnexpectedResultLength(); +error UnexpectedResultMismatch(); + +/// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses. +contract QueryDemo is QueryResponse { + using BytesParsing for bytes; + + struct ChainEntry { + uint16 chainID; + address contractAddress; + uint256 counter; + uint256 blockNum; + uint256 blockTime; + } + + address private immutable owner; + uint16 private immutable myChainID; + mapping(uint16 => ChainEntry) private counters; + uint16[] private foreignChainIDs; + + bytes4 public GetMyCounter = bytes4(hex"916d5743"); + + constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) { + if (_owner == address(0)) { + revert InvalidOwner(); + } + owner = _owner; + + myChainID = _myChainID; + counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0); + } + + // updateRegistration should be used to add the other chains and to set / update contract addresses. + function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner { + if (counters[_chainID].chainID == 0) { + foreignChainIDs.push(_chainID); + counters[_chainID].chainID = _chainID; + } + + counters[_chainID].contractAddress = _contractAddress; + } + + // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query. + function getMyCounter() public view returns (uint256) { + return counters[myChainID].counter; + } + + // getState() returns this chain's view of all the counters. It is meant to be used in the front end. + function getState() public view returns (ChainEntry[] memory) { + ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1); + ret[0] = counters[myChainID]; + uint256 length = foreignChainIDs.length; + + for (uint256 i = 0; i < length;) { + ret[i + 1] = counters[foreignChainIDs[i]]; + unchecked { + ++i; + } + } + + return ret; + } + + // @notice Takes the cross chain query response for the other counters, stores the results for the other chains, and updates the counter for this chain. + function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public { + ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures); + uint256 numResponses = r.responses.length; + if (numResponses != foreignChainIDs.length) { + revert UnexpectedResultLength(); + } + + for (uint256 i = 0; i < numResponses;) { + // Create a storage pointer for frequently read and updated data stored on the blockchain + ChainEntry storage chainEntry = counters[r.responses[i].chainId]; + if (chainEntry.chainID != foreignChainIDs[i]) { + revert InvalidForeignChainID(); + } + + EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]); + + // Validate that update is not obsolete + validateBlockNum(eqr.blockNum, chainEntry.blockNum); + + // Validate that update is not stale + validateBlockTime(eqr.blockTime, block.timestamp - 300); + + if (eqr.result.length != 1) { + revert UnexpectedResultMismatch(); + } + + // Validate addresses and function signatures + address[] memory validAddresses = new address[](1); + bytes4[] memory validFunctionSignatures = new bytes4[](1); + validAddresses[0] = chainEntry.contractAddress; + validFunctionSignatures[0] = GetMyCounter; + + validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures); + + require(eqr.result[0].result.length == 32, "result is not a uint256"); + + chainEntry.blockNum = eqr.blockNum; + chainEntry.blockTime = eqr.blockTime / 1_000_000; + chainEntry.counter = abi.decode(eqr.result[0].result, (uint256)); + + unchecked { + ++i; + } + } + + counters[myChainID].blockNum = block.number; + counters[myChainID].blockTime = block.timestamp; + counters[myChainID].counter += 1; + } + + modifier onlyOwner() { + if (owner != msg.sender) { + revert InvalidOwner(); + } + _; + } +} + ``` + +## Submit a Query Response On-Chain + +The `QueryProxyQueryResponse` result requires a slight tweak when submitting to the contract to match the format of `function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures)`. A helper function, `signaturesToEvmStruct`, is provided in the SDK for this. + +This example submits the transaction to the demo contract: + +```jsx +const tx = await contract.updateCounters( + `0x${response.data.bytes}`, + signaturesToEvmStruct(response.data.signatures) +); +``` --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/overview/ @@ -14713,7 +15101,7 @@ categories: Reference Wormhole supports many blockchains across mainnet, testnet, and devnets. You can use these tables to verify if your desired chains are supported by the Wormhole products you plan to include in your integration. -## Networks +## Supported Networks by Product @@ -15276,22 +15664,274 @@ If the slippage tolerance is set too low, the user may receive USDC on the desti Doc-Content: https://wormhole.com/docs/products/settlement/get-started/ --- BEGIN CONTENT --- -TODO ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- --- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. +title: Get Started +description: Perform a cross-chain token swap using Wormhole Settlement and the Mayan Swift route with the TypeScript SDK on mainnet. categories: Settlement, Transfer --- -# Build on the Wormhole Liquidity Layer +# Get Started -## Introduction +[Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. + +By the end, you'll have a working script that: + +- Resolves token transfer routes using Mayan Swift +- Quotes and validates the best route +- Initiates a swap on a source chain and completes the transfer on a destination chain + +!!! note + Mayan Swift currently supports **mainnet only**. Attempting to run this demo on a testnet will fail. + +## Prerequisites + +Before you begin, ensure you have the following: + +- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed on your machine +- Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#settlement){target=\_blank} + +This example uses Ethereum as the source chain and Solana as the destination. As a result, you'll need an Ethereum wallet with ETH for gas and a Solana wallet with SOL for fees. You can adapt the example to match your preferred chains. + +## Set Up a Project + +Start by scaffolding a basic Node.js project and installing the required SDKs. + +1. Create a new project folder: + + ```bash + mkdir settlement-swap + cd settlement-swap + npm init -y + ``` + +2. Install the required dependencies: + + ```bash + npm install @wormhole-foundation/sdk-connect \ + @wormhole-foundation/sdk-evm \ + @wormhole-foundation/sdk-solana \ + @mayanfinance/wormhole-sdk-route \ + dotenv + npm install -D typescript tsx + ``` + +3. Create the file structure: + + ```bash + mkdir src + touch src/helpers.ts src/swap.ts .env .gitignore + ``` + +4. Set up secure access to your wallets. This guide assumes you are loading your `MAINNET_ETH_PRIVATE_KEY` and `MAINNET_SOL_PRIVATE_KEY` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [cast wallet](https://book.getfoundry.sh/reference/cast/cast-wallet/){target=_blank}. + + !!! warning + If you use a .env file during development, add it to your .gitignore to exclude it from version control. Never commit private keys or mnemonics to your repository. + +## Perform a Token Swap + +This section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source and destination chain signers. + +Then, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and completes the transfer on Solana. + +1. Open `helper.ts` and define the `getSigner` utility function to load private keys, instantiate signers for Ethereum and Solana, and return the signers along with the Wormhole-formatted address: + + ```ts title="src/helpers.ts" + import { + Chain, + ChainAddress, + ChainContext, + Network, + Signer, + Wormhole, +} from '@wormhole-foundation/sdk-connect'; +import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm'; +import { getSolanaSigner } from '@wormhole-foundation/sdk-solana'; + +/** + * Returns a signer for the given chain using locally scoped credentials. + * The required values (MAINNET_ETH_PRIVATE_KEY, MAINNET_SOL_PRIVATE_KEY) + * must be loaded securely beforehand, for example via a keystore, + * secrets manager, or environment variables (not recommended). + */ +// Define Transfer Interface +export interface SignerContext { + signer: Signer; + address: ChainAddress; +} + +export async function getSigner( + chain: ChainContext +): Promise> { + let signer: Signer; + const platform = chain.platform.utils()._platform; + switch (platform) { + case 'Solana': + signer = await getSolanaSigner( + await chain.getRpc(), + getEnv('MAINNET_SOL_PRIVATE_KEY') + ); + break; + case 'Evm': + signer = await getEvmSignerForKey( + await chain.getRpc(), + getEnv('MAINNET_ETH_PRIVATE_KEY') + ); + break; + default: + throw new Error('Unrecognized platform: ' + platform); + } + + return { + signer: signer as Signer, + address: Wormhole.chainAddress(chain.chain, signer.address()), + }; +} + + ``` + +2. In `swap.ts`, add the following script, which will handle all of the logic required to perform the token swap: + + ```ts title="src/swap.ts" + import { Wormhole, routes } from '@wormhole-foundation/sdk-connect'; +import { EvmPlatform } from '@wormhole-foundation/sdk-evm'; +import { SolanaPlatform } from '@wormhole-foundation/sdk-solana'; +import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route'; +import { getSigner } from './helpers'; + +(async function () { + // Setup + const wh = new Wormhole('Mainnet', [EvmPlatform, SolanaPlatform]); + + const sendChain = wh.getChain('Ethereum'); + const destChain = wh.getChain('Solana'); + + // To transfer native ETH on Ethereum to native SOL on Solana + const source = Wormhole.tokenId(sendChain.chain, 'native'); + const destination = Wormhole.tokenId(destChain.chain, 'native'); + + // Create a new Wormhole route resolver, adding the Mayan route to the default list + // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type, + // but MayanRouteSWIFT is compatible and works as intended in this context. + const resolver = wh.resolver([MayanRouteSWIFT]); + + // Show supported tokens + const dstTokens = await resolver.supportedDestinationTokens( + source, + sendChain, + destChain + ); + console.log(dstTokens.slice(0, 5)); + + // Load signers and addresses from helpers + const sender = await getSigner(sendChain); + const receiver = await getSigner(destChain); + + // Creating a transfer request fetches token details + // since all routes will need to know about the tokens + const tr = await routes.RouteTransferRequest.create(wh, { + source, + destination, + }); + + // Resolve the transfer request to a set of routes that can perform it + const foundRoutes = await resolver.findRoutes(tr); + const bestRoute = foundRoutes[0]!; + + // Specify the amount as a decimal string + const transferParams = { + amount: '0.002', + options: bestRoute.getDefaultOptions(), + }; + + // Validate the queries route + let validated = await bestRoute.validate(tr, transferParams); + if (!validated.valid) { + console.error(validated.error); + return; + } + console.log('Validated: ', validated); + + const quote = await bestRoute.quote(tr, validated.params); + if (!quote.success) { + console.error(`Error fetching a quote: ${quote.error.message}`); + return; + } + console.log('Quote: ', quote); + + // Initiate the transfer + const receipt = await bestRoute.initiate( + tr, + sender.signer, + quote, + receiver.address + ); + console.log('Initiated transfer with receipt: ', receipt); + + await routes.checkAndCompleteTransfer( + bestRoute, + receipt, + receiver.signer, + 15 * 60 * 1000 + ); +})(); + ``` + +3. Execute the script to initiate and complete the transfer: + + ```bash + npx tsx src/swap.ts + ``` + + If successful, you’ll see terminal output like this: + +
    +npx tsx src/swap.ts +Validated: { valid: true, ... } +Quote: { success: true, ... } +Initiated transfer with receipt: ... +Checking transfer state... +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: SourceInitiated +Current Transfer State: DestinationFinalized + +
    + +Congratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement. + +## Customize the Integration + +You can tailor the example to your use case by adjusting: + +- **Tokens and chains**: Use `getSupportedTokens()` to explore what's available. +- **Source and destination chains**: Modify `sendChain` and `destChain` in `swap.ts`. +- **Transfer settings**: Update the amount or route parameters. +- **Signer management**: Modify `src/helpers.ts` to integrate with your preferred wallet setup. + +## Next Steps + +Once you've chosen a path, follow the corresponding guide to start building: + +- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. + +--- END CONTENT --- + +Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ +--- BEGIN CONTENT --- +--- +title: Wormhole Settlement Liquidity Layer +description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. +categories: Settlement, Transfer +--- + +# Build on the Wormhole Liquidity Layer + +## Introduction + +The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. ## EVM Functions @@ -16435,7 +17075,7 @@ categories: Token-Bridge, Transfers Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} enables seamless multichain token transfers by locking tokens on a source chain and minting equivalent wrapped tokens on a destination chain. This mechanism preserves token properties such as name, symbol, and decimal precision across chains. -In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. If you're new to transfer modes, see the [Transfer Modes page](TODO){target=\_blank} for a detailed explanation. +In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - **Manual transfer** – where you control each step - **Automatic transfer** – where a relayer finalizes the transfer for you @@ -20879,55 +21519,6 @@ This guide helps you install the SDK, initialize a `Wormhole` instance to suppor If you want to build more advanced integrations, such as token transfers using the Token Bridge or CCTP Bridge, skip ahead to [Next Steps](#next-steps). -## Prerequisites - -Before you begin, make sure you have the following: - - - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed - - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed - -??? example "Project setup instructions" - - Use the following commands to create a TypeScript project: - - 1. Create a directory and initialize a Node.js project: - - ```bash - mkdir wh-ts-demo - cd wh-ts-demo - npm init -y - ``` - - 2. Install TypeScript along with `tsx` (for running TypeScript files) and Node.js type definitions: - - ```bash - npm install --save-dev tsx typescript @types/node - ``` - - 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: - - ```bash - npx tsc --init - ``` - - Make sure your `tsconfig.json` includes the following settings: - - ```json - { - "compilerOptions": { - // es2020 or newer - "target": "es2020", - // Use esnext if you configured your package.json with type: "module" - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } - } - ``` - ## Install the SDK To install the Wormhole TypeScript SDK, use the following command: @@ -20997,48 +21588,203 @@ npm install @wormhole-foundation/sdk-evm ## Initialize the SDK -You must first initialize the main `Wormhole` class to use the SDK. This involves specifying the network (`Mainnet`, `Testnet`, or `Devnet`) and the blockchain platforms your application will interact with. - -1. (Optional) Create a new TypeScript file named `src/main.ts` in your project directory: - - ```bash - mkdir src - touch src/main.ts - ``` +Getting your integration started is simple. First, import Wormhole: -2. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: +```ts +import { wormhole } from '@wormhole-foundation/sdk'; - ```ts title="src/main.ts" - import { wormhole } from '@wormhole-foundation/sdk'; -// Import specific platform modules for the chains you intend to use +import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; +import algorand from '@wormhole-foundation/sdk/algorand'; +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; import evm from '@wormhole-foundation/sdk/evm'; import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +import { getSigner } from './helpers/index.js'; -async function main() { - console.log('Initializing Wormhole SDK...'); +(async function () { + const wh = await wormhole('Testnet', [ + evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); - // Determine the network: "Mainnet", "Testnet", or "Devnet" - const network = 'Testnet'; + const ctx = wh.getChain('Solana'); - // Initialize the SDK with the chosen network and platform contexts - const wh = await wormhole(network, [evm, solana]); + const rcv = wh.getChain('Algorand'); - console.log('Wormhole SDK Initialized!'); -} + const sender = await getSigner(ctx); + const receiver = await getSigner(rcv); -main().catch((e) => { - console.error('Error initializing Wormhole SDK', e); - process.exit(1); -}); - ``` + // Get a Token Bridge contract client on the source + const sndTb = await ctx.getTokenBridge(); -## Fetch Chain Information + // Send the native token of the source chain + const tokenId = Wormhole.tokenId(ctx.chain, 'native'); -Follow these steps to verify that the SDK is properly initialized for the chains you intend to support. + // Bigint amount using `amount` module + const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); -1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: + // Create a transaction stream for transfers + const transfer = sndTb.transfer( + sender.address.address, + receiver.address, + tokenId.address, + amt + ); - ```ts title="src/main.ts" + // Sign and send the transaction + const txids = await signSendWait(ctx, transfer, sender.signer); + console.log('Sent: ', txids); + + // Get the Wormhole message ID from the transaction + const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); + console.log('Wormhole Messages: ', whm); + + const vaa = await wh.getVaa( + // Wormhole Message ID + whm!, + // Protocol:Payload name to use for decoding the VAA payload + 'TokenBridge:Transfer', + // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available + 60_000 + ); + + // Now get the token bridge on the redeem side + const rcvTb = await rcv.getTokenBridge(); + + // Create a transaction stream for redeeming + const redeem = rcvTb.redeem(receiver.address.address, vaa!); + + // Sign and send the transaction + const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); + console.log('Sent: ', rcvTxids); + + // Now check if the transfer is completed according to + // the destination token bridge + const finished = await rcvTb.isTransferCompleted(vaa!); + console.log('Transfer completed: ', finished); +})(); +``` + +Then, import each of the ecosystem [platforms](/docs/tools/typescript-sdk/sdk-reference/#platforms) that you wish to support: + +```ts +import aptos from '@wormhole-foundation/sdk/aptos'; +import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; +import sui from '@wormhole-foundation/sdk/sui'; +``` + +To make the [platform](/docs/tools/typescript-sdk/sdk-reference/#platforms) modules available for use, pass them to the Wormhole constructor and specify the network (`Mainnet`, `Testnet`, or `Devnet`) you want to interact with: + +```ts +evm, + solana, + aptos, + algorand, + cosmwasm, + sui, + ]); +``` + +With a configured `Wormhole` object, you can begin to interact with these chains. + +## Example Usage + +Follow these steps to confirm that the SDK is initialized correctly and can fetch basic chain information for your target chains. + +### Prerequisites + +Before you begin, make sure you have the following: + + - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} installed + - [TypeScript](https://www.typescriptlang.org/download/){target=\_blank} installed + +??? example "Project setup instructions" + + Use the following commands to create a TypeScript project: + + 1. Create a directory and initialize a Node.js project: + + ```bash + mkdir wh-ts-demo + cd wh-ts-demo + npm init -y + ``` + + 2. Install TypeScript, `tsx` (for running TypeScript files), Node.js type definitions, the base Wormhole SDK, and the platform-specific packages for the chains you want to interact with: + + ```bash + npm install --save-dev tsx typescript @types/node @wormhole-foundation/sdk @wormhole-foundation/sdk-evm @wormhole-foundation/sdk-solana + ``` + + 3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command: + + ```bash + npx tsc --init + ``` + + Make sure your `tsconfig.json` includes the following settings: + + ```json + { + "compilerOptions": { + // es2020 or newer + "target": "es2020", + // Use esnext if you configured your package.json with type: "module" + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } + } + ``` + + 4. Initialize the main `Wormhole` class to use the SDK. Create a new TypeScript file named `src/main.ts` in your project directory: + + ```bash + mkdir src + touch src/main.ts + ``` + + 5. Add the following code to initialize the SDK and use the `Wormhole` instance to return the chain ID and RPC for the chains this instance supports: + + ```ts title="src/main.ts" + import { wormhole } from '@wormhole-foundation/sdk'; +// Import specific platform modules for the chains you intend to use +import evm from '@wormhole-foundation/sdk/evm'; +import solana from '@wormhole-foundation/sdk/solana'; + +async function main() { + console.log('Initializing Wormhole SDK...'); + + // Determine the network: "Mainnet", "Testnet", or "Devnet" + const network = 'Testnet'; + + // Initialize the SDK with the chosen network and platform contexts + const wh = await wormhole(network, [evm, solana]); + + console.log('Wormhole SDK Initialized!'); +} + +main().catch((e) => { + console.error('Error initializing Wormhole SDK', e); + process.exit(1); +}); + ``` + +### Fetch Chain Information + +1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports: + + ```ts title="src/main.ts" import { wormhole } from '@wormhole-foundation/sdk'; import evm from '@wormhole-foundation/sdk/evm'; import solana from '@wormhole-foundation/sdk/solana'; @@ -22266,14 +23012,9 @@ description: Explore Wormhole's TypeScript SDK and learn how to perform differen categories: Typescript-SDK --- -# Wormhole TypeScript SDK - -## Introduction - -The Wormhole TypeScript SDK is useful for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole. This package bundles together functions, definitions, and constants that streamline the process of connecting chains and completing transfers using Wormhole. The SDK also offers targeted sub-packages for Wormhole-connected platforms, which allow you to add multichain support without creating outsized dependencies. - -This section covers all you need to know about the functionality and ease of development offered through the Wormhole TypeScript SDK. Take a tour of the package to discover how it helps make integration easier. Learn more about how the SDK abstracts away complexities around concepts like platforms, contexts, and signers. Finally, you'll find guidance on usage, along with code examples, to show you how to use the tools of the SDK. +# Wormhole TypeScript SDK Reference +This page covers all you need to know about the functionality offered through the Wormhole TypeScript SDK.
    @@ -22281,350 +23022,70 @@ This section covers all you need to know about the functionality and ease of dev --- - Find installation instructions for both the meta package and installing specific, individual packages - - [:custom-arrow: Install the SDK](#installation) - -- :octicons-book-16:{ .lg .middle } **Concepts** - - --- - - Understand key concepts and how the SDK abstracts them away. Learn more about platforms, chain context, addresses, and signers + Find installation instructions for both the meta package and installing specific, individual packages. - [:custom-arrow: Explore concepts](#concepts) + [:custom-arrow: Install the SDK](/docs/tools/typescript-sdk/get-started/#install-the-sdk) -- :octicons-file-code-16:{ .lg .middle } **Usage** +- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** --- - Guidance on using the SDK to add seamless interchain messaging to your application, including code examples + Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at available methods, classes, interfaces, and definitions. - [:custom-arrow: Use the SDK](#usage) + [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} -- :octicons-code-square-16:{ .lg .middle } **TSdoc for SDK** +- :octicons-code-square-16:{ .lg .middle } **Source Code** --- - Review the TSdoc for the Wormhole TypeScript SDK for a detailed look at availabel methods, classes, interfaces, and definitions - - [:custom-arrow: View the TSdoc on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\_blank} + Want to go straight to the source? Check out the TypeScript SDK GitHub repository. + + [:custom-arrow: View GitHub Repository](https://github.com/wormhole-foundation/wormhole-sdk-ts/){target=\_blank}
    !!! warning - This package is a work in progress. The interface may change, and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} any issues you find. - -## Installation - -### Basic - -To install the meta package using npm, run the following command in the root directory of your project: - -```bash -npm install @wormhole-foundation/sdk -``` - -This package combines all the individual packages to make setup easier while allowing for tree shaking. - -### Advanced - -Alternatively, you can install a specific set of published packages individually: - -??? interface "`sdk-base` - exposes constants" - - ```sh - npm install @wormhole-foundation/sdk-base - ``` - -??? interface "`sdk-definitions` - exposes contract interfaces, basic types, and VAA payload definitions" - - ```sh - npm install @wormhole-foundation/sdk-definitions - ``` - -??? interface "`sdk-evm` - exposes EVM-specific utilities" - - ```sh - npm install @wormhole-foundation/sdk-evm - ``` - -??? interface "`sdk-evm-tokenbridge` - exposes the EVM Token Bridge protocol client" - - ```sh - npm install @wormhole-foundation/sdk-evm-tokenbridge - ``` - -## Usage - -Getting your integration started is simple. First, import Wormhole: - -```ts -import { wormhole } from '@wormhole-foundation/sdk'; - -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; - -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); - - const ctx = wh.getChain('Solana'); - - const rcv = wh.getChain('Algorand'); - - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); - - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); - - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); - - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); - - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); - - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); - - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); - - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); - - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); - - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); - - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); - - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); -``` - -Then, import each of the ecosystem [platforms](#platforms) that you wish to support: - -```ts -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -``` - - -To make the [platform](#platforms) modules available for use, pass them to the Wormhole constructor: - -```ts -evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); -``` - -With a configured Wormhole object, you can do things like parse addresses for the provided platforms, get a [`ChainContext`](#chain-context) object, or fetch VAAs. - -```ts - -``` - -You can retrieve a VAA as follows. In this example, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will vary by network. - -```ts -// Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); -``` - -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; - -import { Wormhole, amount, signSendWait } from '@wormhole-foundation/sdk'; -import algorand from '@wormhole-foundation/sdk/algorand'; -import aptos from '@wormhole-foundation/sdk/aptos'; -import cosmwasm from '@wormhole-foundation/sdk/cosmwasm'; -import evm from '@wormhole-foundation/sdk/evm'; -import solana from '@wormhole-foundation/sdk/solana'; -import sui from '@wormhole-foundation/sdk/sui'; -import { getSigner } from './helpers/index.js'; - -(async function () { - const wh = await wormhole('Testnet', [ - evm, - solana, - aptos, - algorand, - cosmwasm, - sui, - ]); - - const ctx = wh.getChain('Solana'); - - const rcv = wh.getChain('Algorand'); - - const sender = await getSigner(ctx); - const receiver = await getSigner(rcv); - - // Get a Token Bridge contract client on the source - const sndTb = await ctx.getTokenBridge(); - - // Send the native token of the source chain - const tokenId = Wormhole.tokenId(ctx.chain, 'native'); - - // Bigint amount using `amount` module - const amt = amount.units(amount.parse('0.1', ctx.config.nativeTokenDecimals)); - - // Create a transaction stream for transfers - const transfer = sndTb.transfer( - sender.address.address, - receiver.address, - tokenId.address, - amt - ); - - // Sign and send the transaction - const txids = await signSendWait(ctx, transfer, sender.signer); - console.log('Sent: ', txids); - - // Get the Wormhole message ID from the transaction - const [whm] = await ctx.parseTransaction(txids[txids.length - 1]!.txid); - console.log('Wormhole Messages: ', whm); - - const vaa = await wh.getVaa( - // Wormhole Message ID - whm!, - // Protocol:Payload name to use for decoding the VAA payload - 'TokenBridge:Transfer', - // Timeout in milliseconds, depending on the chain and network, the VAA may take some time to be available - 60_000 - ); - - // Now get the token bridge on the redeem side - const rcvTb = await rcv.getTokenBridge(); - - // Create a transaction stream for redeeming - const redeem = rcvTb.redeem(receiver.address.address, vaa!); - - // Sign and send the transaction - const rcvTxids = await signSendWait(rcv, redeem, receiver.signer); - console.log('Sent: ', rcvTxids); - - // Now check if the transfer is completed according to - // the destination token bridge - const finished = await rcvTb.isTransferCompleted(vaa!); - console.log('Transfer completed: ', finished); -})(); - ``` - -Optionally, you can override the default configuration with a partial `WormholeConfig` object to specify particular fields, such as a different RPC endpoint. - -```ts -const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, -}); -``` - -??? code "View the complete script" - ```ts - import { wormhole } from '@wormhole-foundation/sdk'; -import solana from '@wormhole-foundation/sdk/solana'; -(async function () { - const wh = await wormhole('Testnet', [solana], { - chains: { - Solana: { - contracts: { - coreBridge: '11111111111111111111111111111', - }, - rpc: 'https://api.devnet.solana.com', - }, - }, - }); - console.log(wh.config.chains.Solana); -})(); - ``` + This package is a work in progress. The interface may change, and there are likely bugs. Please [report any issues](https://github.com/wormhole-foundation/connect-sdk/issues){target=\_blank} you find. ## Concepts -Understanding several higher-level Wormhole concepts and how the SDK abstracts them away will help you use the tools most effectively. The following sections will introduce and discuss the concepts of platforms, chain contexts, addresses, signers, and protocols, how they are used in the Wormhole context, and how the SDK helps ease development in each conceptual area. +Understanding key Wormhole concepts—and how the SDK abstracts them—will help you use the tools more effectively. The following sections cover platforms, chain contexts, addresses, signers, and protocols, explaining their roles in Wormhole and how the SDK simplifies working with them. ### Platforms -While every chain has unique attributes, chains from the same platform typically have standard functionalities they share. The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: +The SDK includes `Platform` modules, which create a standardized interface for interacting with the chains of a supported platform. The contents of a module vary by platform but can include: -- Protocols, such as [Wormhole core](#wormhole-core), preconfigured to suit the selected platform +- [Protocols](#protocols) preconfigured to suit the selected platform - Definitions and configurations for types, signers, addresses, and chains - Helpers configured for dealing with unsigned transactions on the selected platform -These modules also import and expose essential functions and define types or constants from the chain's native ecosystem to reduce the dependencies needed to interact with a chain using Wormhole. Rather than installing the entire native package for each desired platform, you can install a targeted package of standardized functions and definitions essential to connecting with Wormhole, keeping project dependencies as slim as possible. +These modules expose key functions and types from the native ecosystem, reducing the need for full packages and keeping dependencies lightweight. +??? interface "Supported platform modules" -Wormhole currently supports the following platforms: + | Platform | Installation Command | + |----------|----------------------------------------------------| + | EVM |
    ```@wormhole-foundation/sdk-evm```
    | + | Solana |
    ```@wormhole-foundation/sdk-solana```
    | + | Algorand |
    ```@wormhole-foundation/sdk-algorand```
    | + | Aptos |
    ```@wormhole-foundation/sdk-aptos```
    | + | Cosmos |
    ```@wormhole-foundation/sdk-cosmwasm```
    | + | Sui |
    ```@wormhole-foundation/sdk-sui```
    | -- EVM -- Solana -- Cosmos -- Sui -- Aptos -- Algorand - -See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. + See the [Platforms folder of the TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main/platforms){target=\_blank} for an up-to-date list of the platforms supported by the Wormhole TypeScript SDK. ### Chain Context -The `definitions` package of the SDK includes the `ChainContext` class, which creates an interface for working with connected chains in a standardized way. This class contains the network, chain, and platform configurations for connected chains and cached RPC and protocol clients. The `ChainContext` class also exposes chain-specific methods and utilities. Much of the functionality comes from the `Platform` methods but some specific chains may have overridden methods via the context. This is also where the `Network`, `Chain`, and `Platform` type parameters which are used throughout the package are defined. +`ChainContext` (from the `@wormhole-foundation/sdk-definitions` package) provides a unified interface for interacting with connected chains. It: + +- Holds network, chain, and platform configurations +- Caches RPC and protocol clients +- Exposes both platform-inherited and chain-specific methods +- Defines the core types used across the SDK: `Network`, `Chain`, and `Platform` ```ts +// Get the chain context for the source and destination chains +// This is useful to grab direct clients for the protocols const srcChain = wh.getChain(senderAddress.chain); const dstChain = wh.getChain(receiverAddress.chain); @@ -22634,7 +23095,7 @@ srcChain.getRpcClient(); // => RpcClient<'Evm'> ### Addresses -The SDK uses the `UniversalAddress` class to implement the `Address` interface, which all address types must implement. Addresses from various networks are parsed into their byte representation and modified as needed to ensure they are exactly 32 bytes long. Each platform also has an address type that understands the native address formats, referred to as `NativeAddress.` These abstractions allow you to work with addresses consistently regardless of the underlying chain. +The SDK uses the `UniversalAddress` class to implement the `Address` interface, standardizing address handling across chains. All addresses are parsed into a 32-byte format. Each platform also defines a `NativeAddress` type that understands its native format. These abstractions ensure consistent cross-chain address handling. ```ts // It's possible to convert a string address to its Native address @@ -22660,27 +23121,23 @@ const emitterAddr = ethAddr.toUniversalAddress().toString(); ### Tokens -Similar to the `ChainAddress` type, the `TokenId` type provides the chain and address of a given token. The following snippet introduces `TokenId`, a way to uniquely identify any token, whether it's a standard token or a blockchain's native currency (like ETH for Ethereum). - -Wormhole uses their contract address to create a `TokenId` for standard tokens. For native currencies, Wormhole uses the keyword `native` instead of an address. This makes it easy to work with any type of token consistently. - -Finally, the snippet demonstrates how to convert a `TokenId` back into a regular address format when needed. +The `TokenId` type identifies any token by its chain and address. For standardized tokens, Wormhole uses the token's contract address. For native currencies (e.g., ETH on Ethereum), it uses the keyword `native`. This ensures consistent handling of all tokens. ```ts +// Get the TokenId for an ERC-20 token const sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...'); - +// Get the TokenId for native ETH const gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native'); - +// Convert a TokenId back to a string const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...' ``` ### Signers -Certain methods of signing transactions require a `Signer` interface in the SDK. Depending on the specific requirements, this interface can be fulfilled by either a `SignOnlySigner` or a `SignAndSendSigner`. A signer can be created by wrapping an offline or web wallet. +The SDK's `Signer` interface can be implemented as either a `SignOnlySigner` or a `SignAndSendSigner`, created by wrapping an offline or web wallet: -A `SignOnlySigner` is used when the signer isn't connected to the network or prefers not to broadcast transactions themselves. It accepts an array of unsigned transactions and returns an array of signed and serialized transactions. Before signing, the transactions may be inspected or altered. It's important to note that the serialization process is chain-specific. Refer to the testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank} or [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for an example of how to implement a signer for a specific chain or platform. - -Conversely, a `SignAndSendSigner` is appropriate when the signer is connected to the network and intends to broadcast the transactions. This type of signer also accepts an array of unsigned transactions but returns an array of transaction IDs corresponding to the order of the unsigned transactions. +- **`SignOnlySigner`**: Signs and serializes unsigned transactions without broadcasting them. Transactions can be inspected or modified before signing. Serialization is chain-specific. See testing signers (e.g., [EVM](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts){target=\_blank}, [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts){target=\_blank}) for implementation examples. +- **`SignAndSendSigner`**: Signs and broadcasts transactions, returning their transaction IDs in order. ```ts export type Signer = SignOnlySigner | SignAndSendSigner; @@ -22707,7 +23164,7 @@ export interface SignAndSendSigner { #### Set Up a Signer with Ethers.js -To sign transactions programmatically with the Wormhole SDK, you can use Ethers.js to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: +To sign transactions programmatically with the Wormhole SDK, you can use [Ethers.js](https://docs.ethers.org/){target=\_blank} to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js: ```javascript import { ethers } from 'ethers'; @@ -22736,47 +23193,63 @@ async function sendTransaction() { sendTransaction(); ``` - - **`provider`** - responsible for connecting to the Ethereum network (or any EVM-compatible network). It acts as a bridge between your application and the blockchain, allowing you to fetch data, check the state of the blockchain, and submit transactions - - - **`signer`** - represents the account that will sign the transaction. In this case, you’re creating a signer using the private key associated with the account. The signer is responsible for authorizing transactions by digitally signing them with the private key - - - **`Wallet`** - combines both the provider (for blockchain interaction) and the signer (for transaction authorization), allowing you to sign and send transactions programmatically - -These components work together to create, sign, and submit a transaction to the blockchain. +These components work together to create, sign, and submit a transaction to the blockchain: -???- tip "Managing Private Keys Securely" - Handling private keys is unavoidable, so it’s crucial to manage them securely. Here are some best practices: - - - **Use environment variables** - avoid hardcoding private keys in your code. Use environment variables or secret management tools to inject private keys securely - - **Hardware wallets** - for production environments, consider integrating hardware wallets to keep private keys secure while allowing programmatic access through the SDK +- **`provider`**: Connects to the Ethereum or EVM-compatible network, enabling data access and transaction submission. +- **`signer`** : Represents the account that signs transactions using a private key. +- **`Wallet`**: Combines provider and signer to create, sign, and send transactions programmatically. ### Protocols -While Wormhole is a Generic Message Passing (GMP) protocol, several protocols have been built to provide specific functionality. If available, each protocol will have a platform-specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain. - -#### Wormhole Core +Wormhole is a Generic Message Passing (GMP) protocol with several specialized protocols built on top. Each protocol has platform-specific implementations providing methods to generate transactions or read on-chain state. + +??? interface "Supported protocol modules" + + | Protocol | Installation Command | + |-----------------------|----------------------------------------------------------------| + | EVM Core |
    ```@wormhole-foundation/sdk-evm-core```
    | + | EVM Token Bridge |
    ```@wormhole-foundation/sdk-evm-tokenbridge```
    | + | EVM CCTP |
    ```@wormhole-foundation/sdk-evm-cctp```
    | + | EVM Portico |
    ```@wormhole-foundation/sdk-evm-portico```
    | + | EVM TBTC |
    ```@wormhole-foundation/sdk-evm-tbtc```
    | + | Solana Core |
    ```@wormhole-foundation/sdk-solana-core```
    | + | Solana Token Bridge |
    ```@wormhole-foundation/sdk-solana-tokenbridge```
    | + | Solana CCTP |
    ```@wormhole-foundation/sdk-solana-cctp```
    | + | Solana TBTC |
    ```@wormhole-foundation/sdk-solana-tbtc```
    | + | Algorand Core |
    ```@wormhole-foundation/sdk-algorand-core```
    | + | Algorand Token Bridge |
    ```@wormhole-foundation/sdk-algorand-tokenbridge```
    | + | Aptos Core |
    ```@wormhole-foundation/sdk-aptos-core```
    | + | Aptos Token Bridge |
    ```@wormhole-foundation/sdk-aptos-tokenbridge```
    | + | Aptos CCTP |
    ```@wormhole-foundation/sdk-aptos-cctp```
    | + | Cosmos Core |
    ```@wormhole-foundation/sdk-cosmwasm-core```
    | + | Cosmos Token Bridge |
    ```@wormhole-foundation/sdk-cosmwasm-tokenbridge```
    | + | Sui Core |
    ```@wormhole-foundation/sdk-sui-core```
    | + | Sui Token Bridge |
    ```@wormhole-foundation/sdk-sui-tokenbridge```
    | + | Sui CCTP |
    ```@wormhole-foundation/sdk-sui-cctp```
    | -The core protocol underlies all Wormhole activity. This protocol is responsible for emitting the message containing the information necessary to perform bridging, including the [emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter){target=\_blank}, the [sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence){target=\_blank} for the message, and the payload of the message itself. -The following example demonstrates sending and verifying a message using the Wormhole Core protocol on Solana. - -First, initialize a Wormhole instance for the Testnet environment, specifically for the Solana chain. Then, obtain a signer and its associated address, which will be used to sign transactions. +#### Wormhole Core -Next, get a reference to the core messaging bridge, which is the main interface for interacting with Wormhole's cross-chain messaging capabilities. -The code then prepares a message for publication. This message includes: +The core protocol powers all Wormhole activity by emitting messages containing the [emitter address](/docs/products/reference/glossary/#emitter){target=\_blank}, sequence number, and payload needed for bridging. -- The sender's address -- The message payload (in this case, the encoded string `lol`) -- A nonce (set to `0` here, but can be any user-defined value to uniquely identify the message) -- A [consistency (finality) level](/docs/products/reference/consistency-levels/){target=\_blank} (set to `0`, which determines the finality requirements for the message) +Example workflow on Solana Testnet: -After preparing the message, the next steps are to generate, sign, and send the transaction or transactions required to publish the message on the Solana blockchain. Once the transaction is confirmed, the Wormhole message ID is extracted from the transaction logs. This ID is crucial for tracking the message across chains. +1. Initialize a Wormhole instance for Solana. +2. Obtain a signer and its address. +3. Access the core messaging bridge for cross-chain messaging. +4. Prepare a message with: -The code then waits for the Wormhole network to process and sign the message, turning it into a Verified Action Approval (VAA). This VAA is retrieved in a `Uint8Array` format, with a timeout of 60 seconds. + - Sender's address + - Encoded payload (e.g., "lol") + - Nonce (e.g., 0) + - Consistency level (e.g., 0) -Lastly, the code will demonstrate how to verify the message on the receiving end. A verification transaction is prepared using the original sender's address and the VAA, and finally, this transaction is signed and sent. +5. Generate, sign, and send the transaction to publish the message. +6. Extract the Wormhole message ID from transaction logs for tracking. +7. Wait (up to 60s) to receive the [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} (in `Uint8Array` format) from the Wormhole network. +8. Prepare and send a verification transaction on the receiving chain using the sender's address and the VAA. -???+ code "View the complete script" +???+ example "Example workflow" ```ts import { encoding, signSendWait, wormhole } from '@wormhole-foundation/sdk'; import { getSigner } from './helpers/index.js'; @@ -22831,7 +23304,7 @@ The payload contains the information necessary to perform whatever action is req #### Token Bridge -The most familiar protocol built on Wormhole is the Token Bridge. Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge, which includes methods to generate the transactions required to transfer tokens and methods to generate and redeem attestations. `WormholeTransfer` abstractions are the recommended way to interact with these protocols, but it is possible to use them directly. +The most familiar protocol built on Wormhole is the Token Bridge. Each supported chain has a `TokenBridge` client that provides a consistent interface for transferring tokens and handling attestations. While `WormholeTransfer` abstractions are recommended, direct interaction with the protocol is also supported. ```ts import { signSendWait } from '@wormhole-foundation/sdk'; @@ -22843,8 +23316,6 @@ const txGenerator = tb.createAttestation(token); const txids = await signSendWait(srcChain, txGenerator, src.signer); ``` -Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols){target=\_blank}. - ## Transfers While using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens. @@ -22853,17 +23324,15 @@ The `WormholeTransfer` interface provides a convenient abstraction to encapsulat ### Token Transfers -Performing a token transfer is trivial for any source and destination chains. You can create a new `Wormhole` object to make objects like `TokenTransfer` and `CircleTransfer`, to transfer tokens between chains. +Token transfers between chains are straightforward using Wormhole. Create a `Wormhole` instance and use it to initialize a `TokenTransfer` or `CircleTransfer` object. -The following example demonstrates the process of initiating and completing a token transfer. It starts by creating a `TokenTransfer` object, which tracks the transfer's state throughout its lifecycle. The code then obtains a quote for the transfer, ensuring the amount is sufficient to cover fees and any requested native gas. +The example below shows how to initiate and complete a `TokenTransfer`. After creating the transfer object and retrieving a quote (to verify sufficient amount and fees), the process involves: -The transfer process is divided into three main steps: +1. Initiating the transfer on the source chain. +2. Waiting for attestation (if required). +3. Completing the transfer on the destination chain. -1. Initiating the transfer on the source chain -2. Waiting for the transfer to be attested (if not automatic) -3. Completing the transfer on the destination chain - -For automatic transfers, the process ends after initiation. The code waits for the transfer to be attested for manual transfers and then completes it on the destination chain. +For automatic transfers, the process ends after initiation. Manual transfers require attestation before completion. ```ts const xfer = await wh.tokenTransfer( @@ -23082,17 +23551,15 @@ async function tokenTransfer(
    ``` -Internally, this uses the [TokenBridge](#token-bridge) protocol client to transfer tokens. Like other Protocols, the `TokenBridge` protocol provides a consistent set of methods across all chains to generate a set of transactions for that specific chain. +Internally, this uses the [`TokenBridge`](#token-bridge) protocol client to transfer tokens. ### Native USDC Transfers -You can also transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. Please note that if the transfer is set to `Automatic` mode, a fee for performing the relay will be included in the quote. This fee is deducted from the total amount requested to be sent. For example, if the user wishes to receive `1.0` on the destination, the amount sent should be adjusted to `1.0` plus the relay fee. The same principle applies to native gas drop offs. - -In the following example, the `wh.circleTransfer` function is called with several parameters to set up the transfer. It takes the amount to be transferred (in the token's base units), the sender's chain and address, and the receiver's chain and address. The function also allows specifying whether the transfer should be automatic, meaning it will be completed without further user intervention. +You can transfer native USDC using [Circle's CCTP](https://www.circle.com/en/cross-chain-transfer-protocol){target=\_blank}. If the transfer is set to `automatic`, the quote will include a relay fee, which is deducted from the total amount sent. For example, to receive 1.0 USDC on the destination chain, the sender must cover both the 1.0 and the relay fee. The same applies when including a native gas drop-off. -An optional payload can be included with the transfer, though it's set to undefined in this case. Finally, if the transfer is automatic, you can request that native gas (the blockchain's native currency used for transaction fees) be sent to the receiver along with the transferred tokens. +In the example below, the `wh.circleTransfer` function is used to initiate the transfer. It accepts the amount (in base units), sender and receiver chains and addresses, and an optional automatic flag to enable hands-free completion. You can also include an optional payload (set to `undefined` here) and specify a native gas drop-off if desired. -When waiting for the `VAA`, a timeout of `60,000` milliseconds is used. The amount of time required for the VAA to become available will [vary by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. +When waiting for the VAA, a timeout of `60,000` milliseconds is used. The actual wait time [varies by network](https://developers.circle.com/stablecoins/docs/required-block-confirmations#mainnet){target=\_blank}. ```ts // Amount as bigint (base units) @@ -23476,11 +23943,9 @@ Once the tokens are selected, a `RouteTransferRequest` may be created to provide ); ``` -Choosing the best route is currently left to the developer, but strategies might include sorting by output amount or expected time to complete the transfer (no estimate is currently provided). - -After choosing the best route, extra parameters like `amount`, `nativeGasDropoff`, and `slippage` can be passed, depending on the specific route selected. A quote can be retrieved with the validated request. +Choosing the best route is up to the developer and may involve sorting by output amount or estimated completion time (though no estimate is currently provided). -After successful validation, the code requests a transfer quote. This quote likely includes important details such as fees, estimated time, and the final amount to be received. If the quote is generated successfully, it's displayed for the user to review and decide whether to proceed with the transfer. This process ensures that all transfer details are properly set up and verified before any actual transfer occurs. +Once a route is selected, parameters like `amount`, `nativeGasDropoff`, and `slippage` can be set. After validation, a transfer quote is requested, including fees, estimated time, and final amount. If successful, the quote is shown to the user for review before proceeding, ensuring all details are verified prior to transfer. ```ts 'This route offers the following default options', diff --git a/llms.txt b/llms.txt index 7860374c1..5d1f665d0 100644 --- a/llms.txt +++ b/llms.txt @@ -5,7 +5,6 @@ ## Docs - [AI Resources](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/ai-resources/ai-resources.md): Download LLM-optimized files of the Wormhole documentation, including full content and category-specific resources for AI agents. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/concepts/integration.md): No description available. - [Get Started with CCTP](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/get-started.md): Transfer USDC across chains using Wormhole's CCTP integration with the TypeScript SDK, including setup, attestation, and redemption steps. - [Interacting with CCTP Contracts](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/guides/cctp-contracts.md): Learn how to interact directly with Circle's CCTP Bridge contracts, including TokenMessenger, TokenMinter, and MessageTransmitter. - [CCTP Bridge with Wormhole](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/cctp-bridge/overview.md): Learn how the integration of Circle's CCTP with Wormhole enables secure and efficient native USDC transfers and complex cross-chain interactions. @@ -52,14 +51,9 @@ - [NTT CLI Commands](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/cli-commands.md): A comprehensive guide to the Native Token Transfers (NTT) CLI, detailing commands for managing token transfers across chains within the Wormhole ecosystem. - [Managers and Transceivers](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/native-token-transfers/reference/managers-transceivers.md): Explore the roles of Managers and Transceivers in NTT cross-chain token transfers, including key functions, lifecycle events, and rate-limiting mechanisms. - [Compare Wormhole's Cross-Chain Solutions](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/products.md): Compare Wormhole’s cross-chain solutions for bridging, native transfers, data queries, and governance to enable seamless blockchain interoperability. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/concepts/rpc-basics.md): No description available. - [Queries FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/faqs.md): Wormhole Queries FAQ covering available libraries, query examples, response formats, and details about running query proxy servers. - [Get Started with Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/get-started.md): Follow this guide to run your first multichain, verifiable query with the Wormhole Queries SDK and Proxy, using eth_call to fetch token metadata. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/construct-a-query.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/mock-a-query.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/query-request.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/submit-response.md): No description available. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/verify-response.md): No description available. +- [Use Queries](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/guides/use-queries.md): Explore a simple demo of interacting with Wormhole Queries using an eth_call request to query the supply of wETH on Ethereum using a Wormhole query. - [Queries Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/overview.md): Learn how Wormhole Queries enable smart contracts to fetch real-time, Guardian-verified data across multiple blockchains. - [Queries Supported Methods](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-methods.md): Retrieve multichain data via historical timestamp queries, finality confirmation queries, and Solana lookups. - [Queries Supported Networks](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/queries/reference/supported-networks.md): Reference table of chains supported by Wormhole Queries, including method support, finality, and expected historical data availability. @@ -72,7 +66,7 @@ - [Wormhole Formatted Addresses](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/reference/wormhole-formatted-addresses.md): Explanation of Wormhole formatted 32-byte hex addresses, their conversion, and usage across different blockchain platforms. - [Settlement Protocol Architecture](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md): Explore Wormhole Settlement's native swap protocols—Liquidity Layer, Mayan Swift, and MCTP—for scalable, efficient cross-chain asset transfers. - [Wormhole Settlement FAQs](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md): Frequently asked questions about Wormhole Settlement, including smart contract usage, auction fallback, and message execution. -- [Untitled](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md): No description available. +- [Get Started](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md): Perform a cross-chain token swap using Wormhole Settlement and the Mayan Swift route with the TypeScript SDK on mainnet. - [Wormhole Settlement Liquidity Layer](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md): Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. - [Wormhole Settlement Solver](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md): Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. - [Settlement Overview](https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md): Discover how Settlement enables fast, intent-based token transfers across chains using a unified system of solver auctions and integrated execution routes. From e715ebaae945a61ad83e028bee59169d5ee3298b Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Fri, 30 May 2025 17:43:23 +0200 Subject: [PATCH 43/55] Ilariae/clean up lists (#442) * fixed most todo links * add links * fix lists for connect and ntt * clean up lists * Update products/messaging/overview.md Co-authored-by: Erin Shaben * Update products/native-token-transfers/overview.md Co-authored-by: Erin Shaben --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben --- products/connect/configuration/data.md | 24 ++++----- products/connect/configuration/theme.md | 2 +- products/connect/get-started.md | 8 +-- products/connect/guides/hosted-version.md | 2 +- products/connect/guides/upgrade.md | 24 ++++----- products/connect/overview.md | 14 +++--- products/messaging/overview.md | 36 ++++++------- products/multigov/get-started.md | 4 +- products/multigov/overview.md | 40 +++++++-------- .../native-token-transfers/get-started.md | 4 +- .../guides/evm-launchpad.md | 20 ++++---- .../guides/post-deployment.md | 4 +- products/native-token-transfers/overview.md | 50 +++++++++---------- products/queries/overview.md | 34 ++++++------- products/settlement/get-started.md | 2 +- products/settlement/overview.md | 12 ++--- products/token-bridge/get-started.md | 8 +-- products/token-bridge/overview.md | 38 +++++++------- 18 files changed, 163 insertions(+), 163 deletions(-) diff --git a/products/connect/configuration/data.md b/products/connect/configuration/data.md index a66deb8e9..b7c95d59d 100644 --- a/products/connect/configuration/data.md +++ b/products/connect/configuration/data.md @@ -56,18 +56,18 @@ By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wr The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank}: Manually redeemed Wormhole Token Bridge route. +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank}: Automatically redeemed (relayed) Token Bridge route. +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank}: Manually redeemed CCTP route. +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank}: Automatically redeemed (relayed) CCTP route. +- **`DEFAULT_ROUTES`**: Array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`). +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank}: Function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route. +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}: Function that returns the manually-redeemed NTT route. +- **`nttRoutes(nttConfig)`**: Function that returns both NTT routes as an array. +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank}: Route that offers multiple Mayan protocols. +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank}: Route for Mayan's Swift protocol only. +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank}: Route for Mayan's MCTP protocol only. +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank}: Route for Mayan's original Wormhole transfer protocol. In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. diff --git a/products/connect/configuration/theme.md b/products/connect/configuration/theme.md index e4b54c438..d41479d5b 100644 --- a/products/connect/configuration/theme.md +++ b/products/connect/configuration/theme.md @@ -6,7 +6,7 @@ categories: Connect, Transfer ## Theme & UI Customization -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +This page focuses on how to style the Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. ### Changing the Color Scheme diff --git a/products/connect/get-started.md b/products/connect/get-started.md index 82dc6346c..5425f5d27 100644 --- a/products/connect/get-started.md +++ b/products/connect/get-started.md @@ -66,10 +66,10 @@ Open the `App.tsx` file in your code editor of choice. You will see code similar The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: -- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` -- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains -- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI -- **Defines the theme** - this example sets the mode to `dark` and adds a primary color +- **Defines the network**: Options include `Mainnet`, `Testnet`, or `Devnet`. +- **Defines chains to include**: This example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains. +- **Adds a title to UI**: (Optional) If defined, it will render above the widget in the UI. +- **Defines the theme**: This example sets the mode to `dark` and adds a primary color. ## Interact with Connect diff --git a/products/connect/guides/hosted-version.md b/products/connect/guides/hosted-version.md index 6ddbeff57..e106271a8 100644 --- a/products/connect/guides/hosted-version.md +++ b/products/connect/guides/hosted-version.md @@ -14,7 +14,7 @@ If you're using React, refer to the [Get Started with Connect](/docs/products/co ## Install Connect -To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: +To install the [Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: ```bash npm i @wormhole-foundation/wormhole-connect diff --git a/products/connect/guides/upgrade.md b/products/connect/guides/upgrade.md index 3c5a6e095..2415c81ef 100644 --- a/products/connect/guides/upgrade.md +++ b/products/connect/guides/upgrade.md @@ -20,7 +20,7 @@ These updates ensure better performance and a smoother integration experience. ## Update the Connect Package -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +To begin the migration process, update the Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. Run the following command in your terminal: @@ -123,11 +123,11 @@ The `networks` property, which allowed whitelisting chains, is now renamed `chai ### Update `routes` to Use Route Plugins -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +The `routes` property in Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: +By default, if no `routes` property is set, Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} + - [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -137,7 +137,7 @@ For most use cases, integrators require more than the default routes. The new `r The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: ???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`TokenBridgeRoute`** - manually redeemed Token Bridge route - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - **`CCTPRoute`** - manually redeemed CCTP route - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route @@ -158,7 +158,7 @@ Now that you know the available `route` plugins, let's explore some examples of #### Example: Offer Only CCTP Transfers -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +To configure Connect to offer only USDC transfers via the CCTP route, use the following configuration: ```typescript import WormholeConnect, { @@ -175,7 +175,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -198,7 +198,7 @@ This flexible plugin allows you to combine default routes (such as Token Bridge ### Update the `tokensConfig` Structure -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +In Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. Key Changes to `tokensConfig`: @@ -275,7 +275,7 @@ Key Changes to `tokensConfig`: ### Update NTT Configuration -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +In Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. Key changes: @@ -374,7 +374,7 @@ This change simplifies the configuration process by providing a cleaner, more fl ### Update UI Configuration -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. +In Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. Key UI changes: @@ -498,7 +498,7 @@ Important details: ### Removed Configuration Properties -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. +Several configuration properties have been removed in Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. Removed config keys: @@ -526,7 +526,7 @@ For those using the CDN-hosted version of Wormhole Connect, the package's instal npm install @wormhole-foundation/wormhole-connect@^1.0 ``` -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: +2. After installing the package, you can embed Connect into your page by adding the following code: ```typescript import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; diff --git a/products/connect/overview.md b/products/connect/overview.md index 0c6ca988e..88008006f 100644 --- a/products/connect/overview.md +++ b/products/connect/overview.md @@ -41,19 +41,19 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + - [**Connect**](/docs/products/connect/get-started/): Handles user-friendly asset transfers. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Moves native assets across chains. + - [**Queries**](/docs/products/queries/overview/): Fetches real-time prices for optimal trade execution. - **Cross-Chain Payment Widgets** - - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/get-started/): Facilitates seamless payments in various tokens. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Ensures direct, native asset transfers. - **Web3 Game Asset Transfers** - - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains - - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/get-started/): Provide a user-friendly way to move game tokens across chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/): Handle the underlying lock-and-mint logic securely. ## Next Steps diff --git a/products/messaging/overview.md b/products/messaging/overview.md index 6e9f92aaa..1de0a608d 100644 --- a/products/messaging/overview.md +++ b/products/messaging/overview.md @@ -10,18 +10,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -31,29 +31,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps diff --git a/products/multigov/get-started.md b/products/multigov/get-started.md index 3691e7203..e253770d3 100644 --- a/products/multigov/get-started.md +++ b/products/multigov/get-started.md @@ -42,5 +42,5 @@ MultiGov deployments follow a similar structure on both EVM and Solana. This sec You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: - - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains - - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank}: Configure and deploy MultiGov smart contracts to EVM-compatible chains. + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank}: Launch the Solana staking program and configure spoke chain participation. \ No newline at end of file diff --git a/products/multigov/overview.md b/products/multigov/overview.md index cd7d02275..7b136d69c 100644 --- a/products/multigov/overview.md +++ b/products/multigov/overview.md @@ -12,21 +12,21 @@ MultiGov is a multichain governance system that enables decentralized decision-m MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: -- **Multichain governance** – token holders can vote and execute proposals from any supported chain -- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live -- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain -- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity -- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} +- **Multichain governance**: Token holders can vote and execute proposals from any supported chain. +- **Hub-and-spoke model**: Proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live. +- **Secure vote aggregation**: Vote weights are checkpointed and verified to prevent double voting. +- **Cross-chain proposal execution**: Approved proposals can be executed across multiple chains. +- **Flexible architecture**: Can integrate with any Wormhole-supported blockchain. +- **Upgradeable and extensible**: Supports upgrades across components while preserving vote history and system continuity. +- **Backed by Tally**: Proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank}. ## How It Works -1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling -2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power -3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification -4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends -5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands +1. **Create proposal on hub chain**: Proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling. +2. **Vote from spoke chains**: Token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power. +3. **Transmit votes via Wormhole**: Votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification. +4. **Aggregate and finalize on hub**: The hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends. +5. **Execute actions across chains**: Upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands. @@ -34,20 +34,20 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Vote on treasury actions from any supported chain. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Transmit proposal execution to target chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Optionally move assets. - **Coordinated Protocol Upgrades Across Chains** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Create a unified proposal to upgrade contracts across networks. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Send upgrade instructions as VAAs and deliver execution payloads to target chains. - **Progressive Decentralization for Multichain DAOs** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Extend governance to new chains while preserving coordination. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch on-chain vote weights from remote spokes. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Aggregate results and execute actions via the hub. ## Next Steps diff --git a/products/native-token-transfers/get-started.md b/products/native-token-transfers/get-started.md index 2dd0b64f6..a9486e77a 100644 --- a/products/native-token-transfers/get-started.md +++ b/products/native-token-transfers/get-started.md @@ -189,5 +189,5 @@ In the deployment steps, you will add your supported chains, their token address You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: -- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank}: Deploy NTT on EVM-compatible chains. +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank}: Deploy NTT on Solana. diff --git a/products/native-token-transfers/guides/evm-launchpad.md b/products/native-token-transfers/guides/evm-launchpad.md index 20a4a15f4..97b543fb6 100644 --- a/products/native-token-transfers/guides/evm-launchpad.md +++ b/products/native-token-transfers/guides/evm-launchpad.md @@ -43,8 +43,8 @@ The NTT Launchpad currently supports deployments on the following mainnet chains Once ready, choose an option to proceed: - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token): Deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains. + - [**Expand Your Existing Token**](#expand-your-existing-token): If you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract. ## Launch a Cross-Chain Token @@ -148,8 +148,8 @@ Use the drop-down menu at the top to select the chain you want to configure. The From this section, you can also: - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain + - **Pause the token**: Temporarily turn off transfers on the selected chain. + - **Deploy to a new chain**: Expand your token by deploying it to an additional chain. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) @@ -157,8 +157,8 @@ From this section, you can also: This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers + - **Manager’s Owner**: The owner through the `NTTOwner` proxy. + - **Pauser**: The address authorized to pause transfers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) @@ -168,8 +168,8 @@ Determine and update how transceivers interact with the token. [Transceivers](/d A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + - **Registered Transceivers**: Displays the number of registered transceivers and their addresses. + - **Transceivers Threshold**: A configurable value that must be less than or equal to the number of transceivers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) @@ -177,8 +177,8 @@ A higher transceiver threshold increases security by requiring more approvals be Define the transfer restrictions for each connected network. You can adjust: - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + - **Sending Limits**: The maximum amount of tokens that can be sent from the home chain. + - **Receiving Limits**: The maximum amount of tokens that can be received for each of the supported peer chains. Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. diff --git a/products/native-token-transfers/guides/post-deployment.md b/products/native-token-transfers/guides/post-deployment.md index a98128cfa..b74d3e547 100644 --- a/products/native-token-transfers/guides/post-deployment.md +++ b/products/native-token-transfers/guides/post-deployment.md @@ -10,7 +10,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Consider a streamlined, customizable frontend such as [Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -29,7 +29,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Connect, a customizable widget for cross-chain asset transfers. [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) diff --git a/products/native-token-transfers/overview.md b/products/native-token-transfers/overview.md index bd2181fcc..bb8199eab 100644 --- a/products/native-token-transfers/overview.md +++ b/products/native-token-transfers/overview.md @@ -10,18 +10,18 @@ Native Token Transfers (NTT) provides an adaptable framework for transferring yo ## Key Features -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +- **Control and customization**: Ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls. +- **Advanced rate limiting**: Set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments. +- **Global accountant**: Ensures the amount burned and transferred on chains never exceeds the amount of tokens minted. +- **No wrapped tokens**: Tokens are used directly within their native ecosystem, eliminating intermediary transfer steps. ## Deployment Models NTT offers two operational modes for your existing tokens: -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token +- **Hub-and-spoke**: Locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts. +- **Burn-and-mint**: Burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token. ## Supported Token Standards @@ -35,42 +35,42 @@ NTT does not currently support token standards like ERC-721 (non-fungible tokens Here's a breakdown of the key steps involved when deploying NTT: -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed +- **Prepare tokens**: Ensure your ERC-20 or SPL tokens are ready. +- **Choose deployment model**: Choose your cross-chain token model: either burn-and-mint or hub-and-spoke. +- **Choose deployment tool**: Use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank}. +- **Initialization**: Specify target chains and token details, and set up your CLI environment if using it. +- **Deploy contracts**: Deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees. +- **Finalize configurations**: Grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles. +- **Monitor and maintain**: Verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed. ## Use Cases - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transmits native assets across chains. + - [**Connect**](/docs/products/connect/overview/): Manages user-friendly asset transfers. + - [**Queries**](/docs/products/queries/overview/): Acquires real-time prices for optimal trade execution. - **Borrowing and Lending Across Chains** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Moves collateral as native assets. + - [**Messaging**](/docs/products/messaging/overview/): Propagates loan requests and liquidations across chains. + - [**Queries**](/docs/products/queries/overview/): Retrieves interest rates and asset prices in real-time. - **Gas Abstraction** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Facilitates native token conversion for gas payments. + - [**Messaging**](/docs/products/messaging/overview/): Sends gas fee payments across chains. - **Cross-Chain Payment Widgets** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Ensures direct, native asset transfers. + - [**Connect**](/docs/products/connect/overview/): Facilitates seamless payments in various tokens. - **Cross-Chain Staking** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transfers staked assets natively between networks. + - [**Messaging**](/docs/products/messaging/overview/): Moves staking rewards and governance signals across chains. ## Next Steps diff --git a/products/queries/overview.md b/products/queries/overview.md index a18ef3570..815129ff4 100644 --- a/products/queries/overview.md +++ b/products/queries/overview.md @@ -10,11 +10,11 @@ Queries provide on-demand access to Guardian-attested on-chain data. They allow ## Key Features -- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time -- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation -- **Cross-chain ready** – request data on one chain, use it on another -- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts -- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} +- **On-demand data access**: Fetch price feeds, interest rates, and other data in real-time. +- **Guardian attested**: All data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation. +- **Cross-chain ready**: Request data on one chain, use it on another. +- **Smart contract integration**: Results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts. +- **Chain agnostic**: works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank}. ## How It Works @@ -36,30 +36,30 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch rates and prices in real-time. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Sync actions between chains. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution - - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch live prices optimal trade execution. + - [**Connect**](/docs/products/connect/overview/){target=\_blank}: Handle user-friendly asset transfers. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Moves native tokens. - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch price feeds. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Trigger trades. - **Multichain Prediction Markets** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch market data and odds. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Automates token execution. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Source data from chains. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Ensures tamper-proof data relay across networks. ## Next Steps diff --git a/products/settlement/get-started.md b/products/settlement/get-started.md index 29c56b48a..d85e497d0 100644 --- a/products/settlement/get-started.md +++ b/products/settlement/get-started.md @@ -106,6 +106,6 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: -- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. - [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. diff --git a/products/settlement/overview.md b/products/settlement/overview.md index 9ff6d0553..f8ba77874 100644 --- a/products/settlement/overview.md +++ b/products/settlement/overview.md @@ -89,18 +89,18 @@ To read more about each protocol, check the [architecture documentation](/docs/p - **Cross-Chain Perpetuals** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Provides fast token execution across chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch live prices and manage position state across chains. - **Bridging Intent Library** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Handles user-defined bridge intents. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Triggers cross-chain function calls. - **Multichain Prediction Markets** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Executes token flows between chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Gets market data and tracks state. ## Next Steps diff --git a/products/token-bridge/get-started.md b/products/token-bridge/get-started.md index 256e68a62..436b6626a 100644 --- a/products/token-bridge/get-started.md +++ b/products/token-bridge/get-started.md @@ -12,8 +12,8 @@ Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - - **Manual transfer** – where you control each step - - **Automatic transfer** – where a relayer finalizes the transfer for you + - **Manual transfer**: Where you control each step. + - **Automatic transfer**: Where a relayer finalizes the transfer for you. These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. @@ -97,5 +97,5 @@ To verify the transaction and view its details, copy the transaction hash from t Now that you've completed a manual multichain token transfer, explore these guides to continue building: - - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) - - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains \ No newline at end of file + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank}: Build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic). + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank}: Learn how to issue tokens that work across chains. \ No newline at end of file diff --git a/products/token-bridge/overview.md b/products/token-bridge/overview.md index cbf2960ee..06449193a 100644 --- a/products/token-bridge/overview.md +++ b/products/token-bridge/overview.md @@ -14,21 +14,21 @@ This overview covers Token Bridge's main features, general processes, and possib Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +- **Interoperability**: Transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank}. +- **Lock-and-mint mechanism**: Mint wrapped tokens backed 1:1 by locked assets on the source chain. +- **Preserved metadata**: Ensure that token properties like name, symbol, and decimals persist across chains. +- **Transfer with payload**: Attach arbitrary data to token transfers, enabling the triggering of specific actions. +- **Decentralized security**: Verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity. ## How It Works The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +1. **Attestation**: The token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token. +2. **Locking**: On the source chain, the native token is locked in a custody account. +3. **Message emission**: The [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +4. **Verification**: The VAA is submitted and verified on the destination chain to confirm authenticity. +5. **Minting**: A wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain. This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. @@ -57,23 +57,23 @@ Here are key use cases that highlight the power and versatility of the Token Bri - **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Transfer tokens between chains. + - [**Messaging**](/docs/products/messaging/overview/): Facilitate the distribution and claiming processes of rewards. - **Tokenized Gaming Rewards** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Handle the underlying lock-and-mint logic securely. + - [**Connect**](/docs/products/connect/overview/): Provide a user-friendly way to move game tokens across chains. - **Multichain DeFi Arbitrage** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Enables rapid and secure movement of DeFi assets. + - [**Connect**](/docs/products/connect/overview/): Provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms. ## Next Steps If you are looking for more guided practice, take a look at: -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge \ No newline at end of file +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/): Perform token transfers using the Token Bridge, including manual and automatic transfers. +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/): Build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains. +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/): Craft a multichain token using Wormhole's Portal Bridge. \ No newline at end of file From dde141bce6a839ffce2de767e46fb9ccff678fda Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 11:48:07 -0400 Subject: [PATCH 44/55] update links (#443) --- .../connect/overview/connect-timeline.json | 6 +- .../overview/ntt-timeline.json | 0 .../reference}/supported-networks/cctp.md | 0 .../reference}/supported-networks/connect.md | 0 .../reference}/supported-networks/multigov.md | 0 .../reference}/supported-networks/ntt.md | 0 .../supported-networks/settlement.md | 0 .../supported-networks/token-bridge.md | 0 README.md | 2 +- llms-files/llms-basics.txt | 32 +++---- llms-files/llms-connect.txt | 36 +++---- llms-files/llms-multigov.txt | 34 +++---- llms-files/llms-ntt.txt | 54 +++++------ llms-files/llms-queries.txt | 36 +++---- llms-files/llms-relayers.txt | 36 +++---- llms-files/llms-settlement.txt | 40 ++++---- llms-files/llms-solidity-sdk.txt | 36 +++---- llms-files/llms-token-bridge.txt | 36 +++---- llms-files/llms-transfer.txt | 78 +++++++-------- llms-files/llms-typescript-sdk.txt | 40 ++++---- llms-full.txt | 94 +++++++++---------- .../tutorials/complete-usdc-transfer.md | 2 +- products/connect/guides/upgrade.md | 4 +- products/messaging/guides/core-contracts.md | 2 +- .../messaging/guides/wormhole-relayers.md | 4 +- .../tutorials/cross-chain-contracts.md | 2 +- products/multigov/faqs.md | 2 +- products/native-token-transfers/faqs.md | 4 +- .../guides/deploy-to-solana.md | 14 +-- .../guides/post-deployment.md | 2 +- products/native-token-transfers/overview.md | 2 +- products/products.md | 8 +- products/queries/faqs.md | 2 +- products/queries/guides/use-queries.md | 2 +- products/reference/supported-networks.md | 12 +-- products/settlement/get-started.md | 2 +- products/settlement/guides/liquidity-layer.md | 2 +- products/settlement/guides/solver.md | 2 +- products/settlement/overview.md | 2 +- products/token-bridge/faqs.md | 2 +- .../guides/token-bridge-contracts.md | 2 +- .../tutorials/transfer-workflow.md | 4 +- protocol/architecture.md | 2 +- protocol/infrastructure/core-contracts.md | 2 +- protocol/infrastructure/guardians.md | 2 +- protocol/infrastructure/spy.md | 8 +- protocol/introduction.md | 2 +- protocol/security.md | 4 +- tools/dev-env.md | 2 +- tools/solidity-sdk/sdk-reference.md | 2 +- tools/typescript-sdk/get-started.md | 6 +- 51 files changed, 318 insertions(+), 350 deletions(-) rename .snippets/text/products/{ntt => native-token-transfers}/overview/ntt-timeline.json (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/cctp.md (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/connect.md (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/multigov.md (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/ntt.md (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/settlement.md (100%) rename .snippets/text/{build/start-building => products/reference}/supported-networks/token-bridge.md (100%) diff --git a/.snippets/text/products/connect/overview/connect-timeline.json b/.snippets/text/products/connect/overview/connect-timeline.json index e429d9108..136464fdb 100644 --- a/.snippets/text/products/connect/overview/connect-timeline.json +++ b/.snippets/text/products/connect/overview/connect-timeline.json @@ -1,16 +1,16 @@ [ { - "title": "[Get Started with Connect](Todo)", + "title": "[Get Started with Connect](/docs/products/connect/get-started/)", "content": "Integrate Connect into your React or JavaScript application with minimal setup.", "icon": ":fontawesome-solid-1:" }, { - "title": "[Customize Transfer Logic](Todo)", + "title": "[Customize Transfer Logic](/docs/products/connect/configuration/data/)", "content": "Configure supported chains, tokens, and transfer routes to fit your app's needs.", "icon": ":fontawesome-solid-2:" }, { - "title": "[Customize the UI](Todo)", + "title": "[Customize the UI](/docs/products/connect/configuration/theme/)", "content": "Adapt Connect's interface to match your brand using flexible styling options.", "icon": ":fontawesome-solid-3:" } diff --git a/.snippets/text/products/ntt/overview/ntt-timeline.json b/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json similarity index 100% rename from .snippets/text/products/ntt/overview/ntt-timeline.json rename to .snippets/text/products/native-token-transfers/overview/ntt-timeline.json diff --git a/.snippets/text/build/start-building/supported-networks/cctp.md b/.snippets/text/products/reference/supported-networks/cctp.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/cctp.md rename to .snippets/text/products/reference/supported-networks/cctp.md diff --git a/.snippets/text/build/start-building/supported-networks/connect.md b/.snippets/text/products/reference/supported-networks/connect.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/connect.md rename to .snippets/text/products/reference/supported-networks/connect.md diff --git a/.snippets/text/build/start-building/supported-networks/multigov.md b/.snippets/text/products/reference/supported-networks/multigov.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/multigov.md rename to .snippets/text/products/reference/supported-networks/multigov.md diff --git a/.snippets/text/build/start-building/supported-networks/ntt.md b/.snippets/text/products/reference/supported-networks/ntt.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/ntt.md rename to .snippets/text/products/reference/supported-networks/ntt.md diff --git a/.snippets/text/build/start-building/supported-networks/settlement.md b/.snippets/text/products/reference/supported-networks/settlement.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/settlement.md rename to .snippets/text/products/reference/supported-networks/settlement.md diff --git a/.snippets/text/build/start-building/supported-networks/token-bridge.md b/.snippets/text/products/reference/supported-networks/token-bridge.md similarity index 100% rename from .snippets/text/build/start-building/supported-networks/token-bridge.md rename to .snippets/text/products/reference/supported-networks/token-bridge.md diff --git a/README.md b/README.md index 2ddaf51c7..0d7973cdb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This repository includes AI-ready `.txt` files generated from the documentation - `llms-full.txt` – the complete content of all documentation pages in a single file - `llms-*.txt` – category-specific files for products like NTT, Token Bridge, Connect, and others -These files power AI assistants, enable semantic code search, and integrate Wormhole docs into tools like Cursor. For details, visit the [AI Resources](https://wormhole.com/docs/ai-resources/) page. +These files power AI assistants, enable semantic code search, and integrate Wormhole docs into tools like Cursor. For details, visit the [AI Resources](https://wormhole.com/docs/ai-resources/ai-resources/) page. ## Contributing diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index b307b0a06..a9de0e5e4 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -367,7 +367,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -892,7 +892,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -906,7 +906,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -1001,8 +1001,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -1037,11 +1037,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -1155,7 +1155,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -1250,7 +1250,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -1376,7 +1376,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -1586,11 +1586,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -1620,7 +1620,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -1902,7 +1902,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -1963,12 +1963,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index 047a7d0cc..443cbbdc6 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -1194,8 +1194,8 @@ The `routes` property in Wormhole Connect version 1.0 has significantly improved By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -2143,7 +2143,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -2668,7 +2668,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -2682,7 +2682,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -2777,8 +2777,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -2813,11 +2813,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -2931,7 +2931,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -3026,7 +3026,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -3152,7 +3152,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -3362,11 +3362,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -3396,7 +3396,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -3678,7 +3678,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -3739,12 +3739,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index fed88bb65..9da345919 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -406,7 +406,7 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl ## Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/#multigov). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. ## How are votes aggregated across different chains? @@ -1389,7 +1389,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -1914,7 +1914,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -1928,7 +1928,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -2023,8 +2023,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -2059,11 +2059,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -2177,7 +2177,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -2272,7 +2272,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2398,7 +2398,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -2608,11 +2608,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -2642,7 +2642,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -2924,7 +2924,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2985,12 +2985,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 069be4b63..04d2e6bcb 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -339,7 +339,7 @@ categories: NTT, Transfer ## Do you have an example of how cross-chain lending can be implemented using Wormhole? -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. @@ -458,7 +458,7 @@ To begin transferring tokens to a chain in burning mode when no tokens are locke ## Is there a way to use NTT tokens with chains that don't currently support NTT? -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. For example: - **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) - **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism @@ -1090,7 +1090,7 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT !!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/products/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: @@ -1156,7 +1156,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM Chains](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -1180,15 +1180,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Find answers to common questions about NTT. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - -- :octicons-question-16:{ .lg .middle } **View FAQs** - - --- - - Find answers to common questions about NTT. - - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank}
    --- END CONTENT --- @@ -1395,7 +1387,7 @@ categories: NTT, Transfer To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately @@ -1619,7 +1611,7 @@ Here's a breakdown of the key steps involved when deploying NTT: Follow these steps to get started with NTT: -[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ @@ -2353,7 +2345,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -2878,7 +2870,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -2892,7 +2884,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -2987,8 +2979,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -3023,11 +3015,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -3141,7 +3133,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -3236,7 +3228,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -3362,7 +3354,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -3572,11 +3564,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -3606,7 +3598,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -3888,7 +3880,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -3949,12 +3941,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index a5ceb8c9f..f319a8d4e 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -47,7 +47,7 @@ categories: Queries ## Are there any query examples? -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: +Certainly. You can find a complete guide on the [Use Queries page](/docs/products/queries/guides/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} - [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} @@ -422,7 +422,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe @@ -1157,7 +1157,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -1682,7 +1682,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -1696,7 +1696,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -1791,8 +1791,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -1827,11 +1827,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -1945,7 +1945,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -2040,7 +2040,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2166,7 +2166,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -2376,11 +2376,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -2410,7 +2410,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -2692,7 +2692,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2753,12 +2753,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index faa637851..b8496b20d 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -202,7 +202,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -216,7 +216,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -908,7 +908,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -1433,7 +1433,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -1447,7 +1447,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -1542,8 +1542,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -1578,11 +1578,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -1696,7 +1696,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -1791,7 +1791,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -1917,7 +1917,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -2127,11 +2127,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -2161,7 +2161,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -2443,7 +2443,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2504,12 +2504,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 78b9c4996..6e8db1b6a 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -166,7 +166,7 @@ categories: Settlement, Transfer [Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. -This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=_blank}. By the end, you'll have a working script that: @@ -429,7 +429,7 @@ The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. ### Fast Market Order @@ -545,7 +545,7 @@ A Solver is an off-chain agent responsible for: - Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain - Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. ## Background @@ -866,7 +866,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: -- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. - **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. - **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. --- END CONTENT --- @@ -1228,7 +1228,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -1753,7 +1753,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -1767,7 +1767,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -1862,8 +1862,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -1898,11 +1898,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -2016,7 +2016,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -2111,7 +2111,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2237,7 +2237,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -2447,11 +2447,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -2481,7 +2481,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -2763,7 +2763,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -2824,12 +2824,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 32c3a0201..6d2835cb0 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -799,7 +799,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/tools/cli/get-started/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -1471,7 +1471,7 @@ abstract contract Base { ### Interface for Cross-Chain Messages -The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. +The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} includes several interfaces that are central to cross-chain communication, enabling secure and efficient message delivery. For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: @@ -1961,7 +1961,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -2486,7 +2486,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -2500,7 +2500,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -2595,8 +2595,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -2631,11 +2631,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -2749,7 +2749,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -2844,7 +2844,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2970,7 +2970,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -3180,11 +3180,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -3214,7 +3214,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -3496,7 +3496,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -3557,12 +3557,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index be85045fb..abbc6144a 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -517,7 +517,7 @@ categories: Token-Bridge, Transfer ## Can ownership of wrapped tokens be transferred from the Token Bridge? -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge @@ -851,7 +851,7 @@ categories: Token-Bridge, Transfer Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} page in the Learn section. ## Prerequisites @@ -1499,7 +1499,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -2024,7 +2024,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -2038,7 +2038,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -2133,8 +2133,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -2169,11 +2169,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -2287,7 +2287,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -2382,7 +2382,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -2508,7 +2508,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -2718,11 +2718,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -2752,7 +2752,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -3034,7 +3034,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -3095,12 +3095,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index 25dfee8e2..c272b869d 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -4147,8 +4147,8 @@ The `routes` property in Wormhole Connect version 1.0 has significantly improved By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -5048,7 +5048,7 @@ categories: NTT, Transfer ## Do you have an example of how cross-chain lending can be implemented using Wormhole? -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. @@ -5167,7 +5167,7 @@ To begin transferring tokens to a chain in burning mode when no tokens are locke ## Is there a way to use NTT tokens with chains that don't currently support NTT? -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. For example: - **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) - **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism @@ -5799,7 +5799,7 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT !!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/products/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: @@ -5865,7 +5865,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM Chains](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -5889,15 +5889,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Find answers to common questions about NTT. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - -- :octicons-question-16:{ .lg .middle } **View FAQs** - - --- - - Find answers to common questions about NTT. - - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank}
    --- END CONTENT --- @@ -6104,7 +6096,7 @@ categories: NTT, Transfer To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately @@ -6328,7 +6320,7 @@ Here's a breakdown of the key steps involved when deploying NTT: Follow these steps to get started with NTT: -[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ @@ -6726,8 +6718,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -6762,11 +6754,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -6917,7 +6909,7 @@ categories: Settlement, Transfer [Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. -This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=_blank}. By the end, you'll have a working script that: @@ -7180,7 +7172,7 @@ The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. ### Fast Market Order @@ -7296,7 +7288,7 @@ A Solver is an off-chain agent responsible for: - Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain - Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. ## Background @@ -7617,7 +7609,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: -- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. - **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. - **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. --- END CONTENT --- @@ -7835,7 +7827,7 @@ categories: Token-Bridge, Transfer ## Can ownership of wrapped tokens be transferred from the Token Bridge? -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge @@ -7877,7 +7869,7 @@ categories: Token-Bridge, Transfer Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} page in the Learn section. ## Prerequisites @@ -8525,7 +8517,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -9050,7 +9042,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -9064,7 +9056,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -9159,8 +9151,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -9195,11 +9187,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -9313,7 +9305,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -9408,7 +9400,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -9534,7 +9526,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -9744,11 +9736,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -9778,7 +9770,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -10060,7 +10052,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -10121,12 +10113,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 180ad8af8..04473d949 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -1109,7 +1109,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/tools/cli/get-started/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -1559,9 +1559,9 @@ Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and ## Next Steps - [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) -- [Send a multichain message](TODO: get started messaging) -- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) -- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) +- [Send a multichain message](/docs/products/messaging/get-started/) +- [Transfer assets via the Token Bridge](/docs/products/token-bridge/tutorials/transfer-workflow/) +- [Transfer USDC via the CCTP Bridge](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ @@ -4202,7 +4202,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -4727,7 +4727,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -4741,7 +4741,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -4836,8 +4836,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -4872,11 +4872,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -4990,7 +4990,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -5085,7 +5085,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -5211,7 +5211,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -5421,11 +5421,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -5455,7 +5455,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -5737,7 +5737,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -5798,12 +5798,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/llms-full.txt b/llms-full.txt index ef311a970..3e5da64f9 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -3077,7 +3077,7 @@ description: Learn how to perform USDC cross-chain transfers using Wormhole SDK ## Introduction -In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. +In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/products/cctp-bridge/overview/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. @@ -5299,8 +5299,8 @@ The `routes` property in Wormhole Connect version 1.0 has significantly improved By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -6419,7 +6419,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" @@ -6944,7 +6944,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -6958,7 +6958,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial @@ -7051,7 +7051,7 @@ Wormhole's messaging infrastructure simplifies data transmission, event triggeri By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. -This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. +This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/protocol/introduction/){target=\_blank} to familiarize yourself with the protocol. ## Wormhole Overview @@ -10833,7 +10833,7 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl ## Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/#multigov). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. ## How are votes aggregated across different chains? @@ -11985,7 +11985,7 @@ categories: NTT, Transfer ## Do you have an example of how cross-chain lending can be implemented using Wormhole? -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. @@ -12104,7 +12104,7 @@ To begin transferring tokens to a chain in burning mode when no tokens are locke ## Is there a way to use NTT tokens with chains that don't currently support NTT? -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. For example: - **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) - **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism @@ -12736,7 +12736,7 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT !!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/products/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: @@ -12802,7 +12802,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM Chains](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -12826,15 +12826,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Find answers to common questions about NTT. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - -- :octicons-question-16:{ .lg .middle } **View FAQs** - - --- - - Find answers to common questions about NTT. - - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank}
    --- END CONTENT --- @@ -13041,7 +13033,7 @@ categories: NTT, Transfer To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately @@ -13265,7 +13257,7 @@ Here's a breakdown of the key steps involved when deploying NTT: Follow these steps to get started with NTT: -[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] +[timeline(wormhole-docs/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json)] --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/reference/cli-commands/ @@ -13663,8 +13655,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -13699,11 +13691,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance @@ -13735,7 +13727,7 @@ categories: Queries ## Are there any query examples? -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: +Certainly. You can find a complete guide on the [Use Queries page](/docs/products/queries/guides/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} - [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} @@ -14110,7 +14102,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe @@ -15674,7 +15666,7 @@ categories: Settlement, Transfer [Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. -This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=_blank}. By the end, you'll have a working script that: @@ -15937,7 +15929,7 @@ The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. ### Fast Market Order @@ -16053,7 +16045,7 @@ A Solver is an off-chain agent responsible for: - Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain - Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. ## Background @@ -16374,7 +16366,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: -- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. - **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. - **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. --- END CONTENT --- @@ -17033,7 +17025,7 @@ categories: Token-Bridge, Transfer ## Can ownership of wrapped tokens be transferred from the Token Bridge? -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge @@ -17367,7 +17359,7 @@ categories: Token-Bridge, Transfer Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} page in the Learn section. ## Prerequisites @@ -17767,7 +17759,7 @@ description: Learn to build a cross-chain native token transfer app using Wormho ## Introduction -This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. +This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: @@ -17791,7 +17783,7 @@ Before you begin, ensure you have the following: ## Supported Chains -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. ## Project Setup @@ -18601,7 +18593,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract @@ -19108,7 +19100,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. @@ -19234,7 +19226,7 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    --- END CONTENT --- @@ -19444,11 +19436,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -19478,7 +19470,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/)
    @@ -19760,7 +19752,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? @@ -19821,12 +19813,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: @@ -20696,7 +20688,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/tools/cli/get-started/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages @@ -21368,7 +21360,7 @@ abstract contract Base { ### Interface for Cross-Chain Messages -The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. +The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} includes several interfaces that are central to cross-chain communication, enabling secure and efficient message delivery. For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: @@ -21843,9 +21835,9 @@ Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and ## Next Steps - [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) -- [Send a multichain message](TODO: get started messaging) -- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) -- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) +- [Send a multichain message](/docs/products/messaging/get-started/) +- [Transfer assets via the Token Bridge](/docs/products/token-bridge/tutorials/transfer-workflow/) +- [Transfer USDC via the CCTP Bridge](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/) --- END CONTENT --- Doc-Content: https://wormhole.com/docs/tools/typescript-sdk/guides/protocols-payloads/ diff --git a/products/cctp-bridge/tutorials/complete-usdc-transfer.md b/products/cctp-bridge/tutorials/complete-usdc-transfer.md index aea742857..df2f39d18 100644 --- a/products/cctp-bridge/tutorials/complete-usdc-transfer.md +++ b/products/cctp-bridge/tutorials/complete-usdc-transfer.md @@ -9,7 +9,7 @@ description: Learn how to perform USDC cross-chain transfers using Wormhole SDK ## Introduction -In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/learn/transfers/cctp/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. +In this guide, we will show you how to bridge native USDC across different blockchain networks using [Circle's Cross-Chain Transfer Protocol](/docs/products/cctp-bridge/overview/){target=\_blank} (CCTP) and [Wormhole’s TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/tree/main){target=\_blank}. Traditionally, cross-chain transfers using CCTP involve multiple manual steps, such as initiating the transfer on the source chain, relaying messages between chains, and covering gas fees on both the source and destination chains. Without the TypeScript SDK, developers must handle these operations independently, adding complexity and increasing the chance for errors, mainly when dealing with gas payments on the destination chain and native gas token management. diff --git a/products/connect/guides/upgrade.md b/products/connect/guides/upgrade.md index 2415c81ef..11ede36c8 100644 --- a/products/connect/guides/upgrade.md +++ b/products/connect/guides/upgrade.md @@ -127,8 +127,8 @@ The `routes` property in Connect version 1.0 has significantly improved. Previou By default, if no `routes` property is set, Connect will provide routes for two core protocols: - - [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} - - [CCTP](/docs/learn/transfers/cctp/){target=\_blank} + - [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. diff --git a/products/messaging/guides/core-contracts.md b/products/messaging/guides/core-contracts.md index 92569429f..0ef3e6a29 100644 --- a/products/messaging/guides/core-contracts.md +++ b/products/messaging/guides/core-contracts.md @@ -33,7 +33,7 @@ While the implementation details of the Core Contracts vary by network, the core ### Sending Messages -To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/learn/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/learn/transfers/token-bridge/#token-bridge){target=\_blank}. +To send a message, regardless of the environment or chain, the Core Contract is invoked with a message argument from an [emitter](/docs/products/reference/glossary/#emitter){target=\_blank}. This emitter might be your contract or an existing application such as the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. === "EVM" diff --git a/products/messaging/guides/wormhole-relayers.md b/products/messaging/guides/wormhole-relayers.md index a536c1922..a326383b9 100644 --- a/products/messaging/guides/wormhole-relayers.md +++ b/products/messaging/guides/wormhole-relayers.md @@ -124,7 +124,7 @@ Some implementation details should be considered during development to ensure sa ## Track the Progress of Messages with the Wormhole CLI -While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/build/toolkit/cli/) tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: +While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the [Wormhole CLI](/docs/tools/cli/get-started/){target=\_blank} tool's `status` subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the `worm status` command: === "Mainnet" @@ -138,7 +138,7 @@ While no off-chain programs are required, a developer may want to track the prog worm status testnet ethereum INSERT_TRANSACTION_HASH ``` -See the [Wormhole CLI tool docs](/docs/build/toolkit/cli/) for installation and usage. +See the [Wormhole CLI tool docs](/docs/tools/cli/get-started/){target=\_blank} for installation and usage. ## Step-by-Step Tutorial diff --git a/products/messaging/tutorials/cross-chain-contracts.md b/products/messaging/tutorials/cross-chain-contracts.md index 62b417d3e..72b8c90f7 100644 --- a/products/messaging/tutorials/cross-chain-contracts.md +++ b/products/messaging/tutorials/cross-chain-contracts.md @@ -15,7 +15,7 @@ Wormhole's messaging infrastructure simplifies data transmission, event triggeri By the end of this tutorial, you will have not only built a fully functioning cross-chain message sender and receiver using Solidity but also developed a comprehensive understanding of how to interact with the Wormhole relayer, manage cross-chain costs, and ensure your smart contracts are configured correctly on both source and target chains. -This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/learn/){target=\_blank} to familiarize yourself with the protocol. +This tutorial assumes a basic understanding of Solidity and smart contract development. Before diving in, it may be helpful to review [the basics of Wormhole](/docs/protocol/introduction/){target=\_blank} to familiarize yourself with the protocol. ## Wormhole Overview diff --git a/products/multigov/faqs.md b/products/multigov/faqs.md index a1f8786ec..1a8529f8e 100644 --- a/products/multigov/faqs.md +++ b/products/multigov/faqs.md @@ -21,7 +21,7 @@ MultiGov leverages Wormhole's robust cross-chain communication protocol. It impl ## Can MultiGov integrate with any blockchain? -MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. +MultiGov can potentially integrate with any blockchain supported by Wormhole. However, specific implementations may vary depending on the chain's compatibility with the Ethereum Virtual Machine (EVM) and its smart contract capabilities. [See the full list of supported networks](/docs/products/reference/supported-networks/#multigov). The current implementation of MultiGov supports an EVM hub and both the EVM and SVM for spokes. ## How are votes aggregated across different chains? diff --git a/products/native-token-transfers/faqs.md b/products/native-token-transfers/faqs.md index c976ab682..48faaddbc 100644 --- a/products/native-token-transfers/faqs.md +++ b/products/native-token-transfers/faqs.md @@ -8,7 +8,7 @@ categories: NTT, Transfer ## Do you have an example of how cross-chain lending can be implemented using Wormhole? -Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. +Yes, we have an example of cross-chain lending that leverages [Wormhole’s Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. In this example, collateral deposits (such as ETH on Ethereum) are bridged to a hub chain. Once the collateral is deposited, the borrowed assets, like wrapped BNB, are bridged to Binance Smart Chain. You can explore the full implementation in the [Wormhole Lending Examples repository](https://github.com/wormhole-foundation/example-wormhole-lending){target=_blank} on GitHub. Alternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\_blank} instead of the Token Bridge, which avoids the limitations imposed by governor limits. ETH would be custodied on Ethereum, and BNB on the Binance spoke during this setup. When a user deposits ETH on Ethereum, a core bridge message is sent to the hub for accounting purposes. The hub then emits a message that can be redeemed on Binance to release the BNB. This approach allows for more direct asset control across chains while reducing reliance on Token Bridge limits. @@ -127,7 +127,7 @@ To begin transferring tokens to a chain in burning mode when no tokens are locke ## Is there a way to use NTT tokens with chains that don't currently support NTT? -Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank}. For example: +Yes. NTT tokens can be used with chains that do not support NTT by leveraging the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank}. For example: - **Wrapped token scenario** - a token, such as the W token, can be bridged to non-NTT networks using the Token Bridge. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token) - **Unwrapping requirement** - tokens bridged using the Token Bridge cannot be directly transferred to NTT-supported chains. To transfer them, they must first be unwrapped on the non-NTT chain and then transferred via the appropriate mechanism diff --git a/products/native-token-transfers/guides/deploy-to-solana.md b/products/native-token-transfers/guides/deploy-to-solana.md index faa4530ba..6d0d88371 100644 --- a/products/native-token-transfers/guides/deploy-to-solana.md +++ b/products/native-token-transfers/guides/deploy-to-solana.md @@ -154,7 +154,7 @@ Follow these steps to set the mint authority using the NTT CLI: ## Deploy and Configure NTT !!! warning - If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/build/transfers/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. + If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/products/native-token-transfers/faqs/#how-can-i-specify-a-custom-rpc-for-ntt){target=\_blank} using an `overrides.json` file. For optimal performance, consider using a staked RPC connection from either Triton or Helius. After setting up your deployment, finalize the configuration and deploy the NTT program on Solana by following these steps: @@ -220,7 +220,7 @@ If your deployment fails, it may be due to leftover program buffer accounts taki After deploying NTT on Solana, deploy and integrate it on EVM chains to enable seamless multichain transfers. - [:custom-arrow: Deploy NTT on EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} + [:custom-arrow: Deploy NTT on EVM Chains](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} - :octicons-tools-16:{ .lg .middle } **Test Your Deployment** @@ -244,14 +244,6 @@ If your deployment fails, it may be due to leftover program buffer accounts taki Find answers to common questions about NTT. - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} - -- :octicons-question-16:{ .lg .middle } **View FAQs** - - --- - - Find answers to common questions about NTT. - - [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank}
    diff --git a/products/native-token-transfers/guides/post-deployment.md b/products/native-token-transfers/guides/post-deployment.md index b74d3e547..11a2172d2 100644 --- a/products/native-token-transfers/guides/post-deployment.md +++ b/products/native-token-transfers/guides/post-deployment.md @@ -9,7 +9,7 @@ categories: NTT, Transfer To offer the best user experience and ensure the most robust deployment, Wormhole contributors recommend the following after you have deployed Native Token Transfers (NTT): - Implement a robust testing plan for your multichain token before launching -- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/build/transfers/native-token-transfers/configuration/){target=\_blank} for more details on ownership and rate limits +- Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits - Consider a streamlined, customizable frontend such as [Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately diff --git a/products/native-token-transfers/overview.md b/products/native-token-transfers/overview.md index bb8199eab..f04579496 100644 --- a/products/native-token-transfers/overview.md +++ b/products/native-token-transfers/overview.md @@ -76,4 +76,4 @@ Here's a breakdown of the key steps involved when deploying NTT: Follow these steps to get started with NTT: -[timeline(wormhole-docs/.snippets/text/products/ntt/overview/ntt-timeline.json)] \ No newline at end of file +[timeline(wormhole-docs/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json)] \ No newline at end of file diff --git a/products/products.md b/products/products.md index a2082851e..0c524ceda 100644 --- a/products/products.md +++ b/products/products.md @@ -17,8 +17,8 @@ Beyond transfers, Wormhole extends interoperability with tools for cross-chain d Wormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements. - [**Native Token Transfers (NTT)**](/docs/products/native-token-transfers/overview/){target=\_blank} - a mechanism to transfer native tokens cross-chain seamlessly without conversion to a wrapped asset. Best for projects that require maintaining token fungibility and native chain functionality across multiple networks -- [**Token Bridge**](/docs/learn/transfers/token-bridge/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages -- [**Settlement**](/docs/learn/messaging/wormhole-settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods +- [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} - a bridging solution that uses a lock and mint mechanism. Best for projects that need cross-chain liquidity using wrapped assets and the ability to send messages +- [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - intent-based protocols enabling fast multichain transfers, optimized liquidity flows, and interoperability without relying on traditional bridging methods
    @@ -53,11 +53,11 @@ Beyond asset transfers, Wormhole provides additional tools for cross-chain data ## Bridging UI -[**Connect**](/docs/build/transfers/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. +[**Connect**](/docs/products/connect/overview/){target=\_blank} is a pre-built bridging UI for cross-chain token transfers, requiring minimal setup. Best for projects seeking an easy-to-integrate UI for bridging without modifying contracts. ## Real-time Data -[**Queries**](/docs/build/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. +[**Queries**](/docs/products/queries/overview/){target=\_blank} is a data retrieval service to fetch on-chain data from multiple networks. Best for applications that need multichain analytics, reporting, and data aggregation. ## Multichain Governance diff --git a/products/queries/faqs.md b/products/queries/faqs.md index c3fe4f198..326c14066 100644 --- a/products/queries/faqs.md +++ b/products/queries/faqs.md @@ -21,7 +21,7 @@ categories: Queries ## Are there any query examples? -Certainly. You can find a complete guide on the [Use Queries page](/docs/build/queries/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: +Certainly. You can find a complete guide on the [Use Queries page](/docs/products/queries/guides/use-queries/){target=\_blank}. Additionally, you can find full code examples in the following repositories: - [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\_blank} - [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\_blank} diff --git a/products/queries/guides/use-queries.md b/products/queries/guides/use-queries.md index 0223edc44..b67bc76cd 100644 --- a/products/queries/guides/use-queries.md +++ b/products/queries/guides/use-queries.md @@ -100,7 +100,7 @@ anvil --fork-url https://ethereum.publicnode.com In order for mock requests to verify against the Mainnet Core Contract, you need to replace the current Guardian set with the single Devnet key used by the mock. -Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/build/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. +Here's an example for Ethereum Mainnet, where the `-a` parameter is the [Core Contract address](/docs/products/reference/contract-addresses/#core-contracts){target=\_blank} on that chain. ```jsx npx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe diff --git a/products/reference/supported-networks.md b/products/reference/supported-networks.md index feef5b767..21a297181 100644 --- a/products/reference/supported-networks.md +++ b/products/reference/supported-networks.md @@ -10,9 +10,9 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can ## Supported Networks by Product ---8<-- 'text/build/start-building/supported-networks/connect.md' ---8<-- 'text/build/start-building/supported-networks/ntt.md' ---8<-- 'text/build/start-building/supported-networks/token-bridge.md' ---8<-- 'text/build/start-building/supported-networks/cctp.md' ---8<-- 'text/build/start-building/supported-networks/settlement.md' ---8<-- 'text/build/start-building/supported-networks/multigov.md' \ No newline at end of file +--8<-- 'text/products/reference/supported-networks/connect.md' +--8<-- 'text/products/reference/supported-networks/ntt.md' +--8<-- 'text/products/reference/supported-networks/token-bridge.md' +--8<-- 'text/products/reference/supported-networks/cctp.md' +--8<-- 'text/products/reference/supported-networks/settlement.md' +--8<-- 'text/products/reference/supported-networks/multigov.md' \ No newline at end of file diff --git a/products/settlement/get-started.md b/products/settlement/get-started.md index d85e497d0..19312fa15 100644 --- a/products/settlement/get-started.md +++ b/products/settlement/get-started.md @@ -8,7 +8,7 @@ categories: Settlement, Transfer [Settlement](/docs/products/settlement/overview/){target=\_blank} is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how. -This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](docs/tools/typescript-sdk/get-started/){target=_blank}. +This guide walks you through performing a real token swap using the [Mayan Swift route](https://mayan.finance){target=_blank}, one of the three integrated Settlement protocols, with the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=_blank}. By the end, you'll have a working script that: diff --git a/products/settlement/guides/liquidity-layer.md b/products/settlement/guides/liquidity-layer.md index 420501d16..28e16a0af 100644 --- a/products/settlement/guides/liquidity-layer.md +++ b/products/settlement/guides/liquidity-layer.md @@ -14,7 +14,7 @@ The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. -See the complete list of [Token Router contract addresses](/docs/build/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. +See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. ### Fast Market Order diff --git a/products/settlement/guides/solver.md b/products/settlement/guides/solver.md index 690080510..93adfc77a 100644 --- a/products/settlement/guides/solver.md +++ b/products/settlement/guides/solver.md @@ -17,7 +17,7 @@ A Solver is an off-chain agent responsible for: - Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain - Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/learn/transfers/settlement/overview/){target=\_blank} page. +For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. ## Background diff --git a/products/settlement/overview.md b/products/settlement/overview.md index f8ba77874..c5ec53511 100644 --- a/products/settlement/overview.md +++ b/products/settlement/overview.md @@ -106,7 +106,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: -- **[Get Started with Settlement](docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. +- **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. - **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. - **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. diff --git a/products/token-bridge/faqs.md b/products/token-bridge/faqs.md index 6497ea9d9..6e3eef596 100644 --- a/products/token-bridge/faqs.md +++ b/products/token-bridge/faqs.md @@ -8,7 +8,7 @@ categories: Token-Bridge, Transfer ## Can ownership of wrapped tokens be transferred from the Token Bridge? -No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. +No, you cannot transfer ownership of wrapped token contracts from the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} because the Token Bridge deploys and retains ownership of these contracts and tokens. - **On EVM chains** - when you attest a token, the Token Bridge deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the Token Bridge contract itself - **On Solana** - the Token Bridge deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the Token Bridge diff --git a/products/token-bridge/guides/token-bridge-contracts.md b/products/token-bridge/guides/token-bridge-contracts.md index 567cb7601..3928ed562 100644 --- a/products/token-bridge/guides/token-bridge-contracts.md +++ b/products/token-bridge/guides/token-bridge-contracts.md @@ -10,7 +10,7 @@ categories: Token-Bridge, Transfer Wormhole's Token Bridge enables seamless cross-chain token transfers using a lock-and-mint mechanism. The bridge locks tokens on the source chain and mints them as wrapped assets on the destination chain. Additionally, the Token Bridge supports [Token Transfers with Messages](/docs/protocol/infrastructure/vaas/#token-transfer-with-message){target=\_blank}, where arbitrary byte payloads can be attached to the token transfer, enabling more complex chain interactions. -This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} page in the Learn section. +This page outlines the core contract methods needed to integrate Token Bridge functionality into your smart contracts. To understand the theoretical workings of the Token Bridge, refer to the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} page in the Learn section. ## Prerequisites diff --git a/products/token-bridge/tutorials/transfer-workflow.md b/products/token-bridge/tutorials/transfer-workflow.md index 020c1bd6b..ecee1f16e 100644 --- a/products/token-bridge/tutorials/transfer-workflow.md +++ b/products/token-bridge/tutorials/transfer-workflow.md @@ -9,7 +9,7 @@ description: Learn to build a cross-chain native token transfer app using Wormho ## Introduction -This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. +This tutorial guides you through building a cross-chain token transfer application using the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} and its [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} method. The Token Bridge method enables secure and efficient cross-chain asset transfers across different blockchain networks, allowing users to move tokens seamlessly. By leveraging Wormhole’s Token Bridge, this guide shows you how to build an application that supports multiple transfer types: @@ -33,7 +33,7 @@ Before you begin, ensure you have the following: ## Supported Chains -The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/build/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. +The Wormhole SDK supports a wide range of EVM and non-EVM chains, allowing you to facilitate cross-chain transfers efficiently. You can find a complete list of supported chains on the [Contract Addresses](/docs/products/reference/contract-addresses/#token-bridge){target=\_blank} page, which includes every network where Wormhole smart contracts are deployed, across both mainnet and testnet. ## Project Setup diff --git a/protocol/architecture.md b/protocol/architecture.md index f077fefee..89b9f82c9 100644 --- a/protocol/architecture.md +++ b/protocol/architecture.md @@ -26,7 +26,7 @@ The preceding diagram outlines the end-to-end flow of multichain communication t ## On-Chain Components -- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your [xDapp](/docs/learn/glossary/#xdapp){target=\_blank} or an existing ecosystem protocol +- **Emitter** - a contract that calls the publish message method on the Core Contract. To identify the message, the Core Contract will write an event to the transaction logs with details about the emitter and sequence number. This may be your cross-chain dApp or an existing ecosystem protocol - **[Wormhole Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank}** - primary contract, this is the contract which the Guardians observe and which fundamentally allows for multichain communication - **Transaction logs** - blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract diff --git a/protocol/infrastructure/core-contracts.md b/protocol/infrastructure/core-contracts.md index 84c4091c7..9eb93872b 100644 --- a/protocol/infrastructure/core-contracts.md +++ b/protocol/infrastructure/core-contracts.md @@ -53,7 +53,7 @@ Multicast refers to simultaneously broadcasting a single message or transaction This multicast-by-default model makes it easy to synchronize state across the entire ecosystem. A blockchain can make its data available to every chain in a single action with low latency, which reduces the complexity of the n^2 problems encountered by routing data to many blockchains. -This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/learn/transfers/token-bridge/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. +This doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} and [Wormhole relayer](/docs/protocol/infrastructure/relayer/){target=\_blank} contracts require that some destination details be passed and verified on the destination chain. Because the VAA creation is separate from relaying, the multicast model does not incur an additional cost when a single chain is targeted. If the data isn't needed on a certain blockchain, don't relay it there, and it won't cost anything. diff --git a/protocol/infrastructure/guardians.md b/protocol/infrastructure/guardians.md index 24ccec754..b05b81226 100644 --- a/protocol/infrastructure/guardians.md +++ b/protocol/infrastructure/guardians.md @@ -95,6 +95,6 @@ These principles combine to create a clear pathway towards a fully trustless int Learn how to use Wormhole Queries to add real-time access to Guardian-attested on-chain data via a REST endpoint to your dApp, enabling secure cross-chain interactions and verifications. - [:custom-arrow: Build with Queries](/docs/build/queries/overview/) + [:custom-arrow: Build with Queries](/docs/products/queries/overview/)
    diff --git a/protocol/infrastructure/spy.md b/protocol/infrastructure/spy.md index 5add5a7f0..900ed8651 100644 --- a/protocol/infrastructure/spy.md +++ b/protocol/infrastructure/spy.md @@ -34,11 +34,11 @@ A Spy can access the following categories of messages shared over the gossip pro - The Spy can detect whether a VAA has been approved by the Guardian Network, making it a valuable tool for applications needing real-time multichain verification -- [Observations](/docs/learn/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network +- [Observations](/docs/products/reference/glossary/#observation){target=\_blank} - emitted by Wormhole's core contracts, observations are picked up by the Guardians and relayed across the network - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events -- [Guardian heartbeats](/docs/learn/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status +- [Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\_blank} - heartbeat messages represent Guardian node status - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network @@ -68,7 +68,7 @@ A Spy can access the following categories of messages shared over the gossip pro For an alternative option to on-demand access to Guardian-attested multichain data, see the Wormhole Queries page. Queries provide a simple, REST endpoint style developer experience. - [:custom-arrow: Explore Queries](/docs/build/queries/overview/) + [:custom-arrow: Explore Queries](/docs/products/queries/overview/) @@ -90,6 +90,6 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) diff --git a/protocol/introduction.md b/protocol/introduction.md index 1ac24ff46..2a77a985b 100644 --- a/protocol/introduction.md +++ b/protocol/introduction.md @@ -37,7 +37,7 @@ Wormhole provides a suite of tools and protocols that support a wide range of us - **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) - **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage [Wormhole’s SDKs](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [APIs](/docs/build/toolkit/#wormhole-api-docs){target=\_blank}, [Wormhole Scan](https://wormholescan.io/){target=\_blank}, and documentation to build and deploy cross-chain applications quickly and efficiently +- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently ## What Isn't Wormhole? diff --git a/protocol/security.md b/protocol/security.md index b62d36e06..8a15064f7 100644 --- a/protocol/security.md +++ b/protocol/security.md @@ -10,12 +10,12 @@ categories: Basics At its core, Wormhole is secured by a network of [Guardian](/docs/protocol/infrastructure/guardians/){target=\_blank} nodes that validate and sign messages. If a super majority (e.g., 13 out of 19) of Guardians sign the same message, it can be considered valid. A smart contract on the target chain will verify the signatures and format of the message before approving any transaction. -- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/learn/glossary/#vaa){target=\_blank}) +- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}) - The Guardian network is currently secured by a collection of 19 of the world's top [validator companies](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\_blank} - Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator - Every Guardian runs full nodes (rather than light nodes) of every blockchain in the Wormhole network, so if a blockchain suffers a consensus attack or hard fork, the blockchain will disconnect from the network rather than potentially produce invalid signed VAAs - Any Signed VAA can be verified as authentic by the Core Contract of any other chain -- [Relayers](/docs/learn/glossary/#relayer){target=\_blank} are considered untrusted in the Wormhole ecosystem +- [Relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} are considered untrusted in the Wormhole ecosystem In summary: diff --git a/tools/dev-env.md b/tools/dev-env.md index 2a4703ed8..9d4c35888 100644 --- a/tools/dev-env.md +++ b/tools/dev-env.md @@ -10,7 +10,7 @@ Developers building for smart contract integration will want to set up a develop ## Tooling Installation -The [Wormhole CLI Tool](/docs/build/toolkit/cli/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. +The [Wormhole CLI Tool](/docs/tools/cli/get-started/){target=\_blank} should be installed regardless of the environments chosen. Each environment has its own set of recommended tools. To begin working with a specific environment, see the recommended tools on the respective [environment page](/docs/products/reference/supported-networks/){target=\_blank}. ## Development Stages diff --git a/tools/solidity-sdk/sdk-reference.md b/tools/solidity-sdk/sdk-reference.md index 06523bcbc..1a9b00872 100644 --- a/tools/solidity-sdk/sdk-reference.md +++ b/tools/solidity-sdk/sdk-reference.md @@ -89,7 +89,7 @@ These security measures ensure messages come from the correct source and are pro ### Interface for Cross-Chain Messages -The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} and [`IWormholeReceiver`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeReceiver.sol){target=\_blank} interfaces are central to cross-chain communication, enabling secure and efficient message delivery. +The Wormhole Solidity SDK interacts with the Wormhole relayer for sending and receiving messages across EVM-compatible chains. The [`IWormholeRelayer`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol){target=\_blank} includes several interfaces that are central to cross-chain communication, enabling secure and efficient message delivery. For detailed information on how to implement these interfaces, refer to the [Wormhole Relayer Interfaces documentation](/docs/products/messaging/guides/wormhole-relayers/#wormhole-relayer-interfaces){target=\_blank}. This section covers: diff --git a/tools/typescript-sdk/get-started.md b/tools/typescript-sdk/get-started.md index 082591d29..6afc59ef7 100644 --- a/tools/typescript-sdk/get-started.md +++ b/tools/typescript-sdk/get-started.md @@ -192,6 +192,6 @@ Congratulations! You’ve successfully installed the Wormhole TypeScript SDK and ## Next Steps - [Get familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/) -- [Send a multichain message](TODO: get started messaging) -- [Transfer wrapped assets via the Token Bridge](TODO: get started token bridge) -- [Transfer USDC via the CCTP Bridge](TODO: get started cctp bridge) +- [Send a multichain message](/docs/products/messaging/get-started/) +- [Transfer assets via the Token Bridge](/docs/products/token-bridge/tutorials/transfer-workflow/) +- [Transfer USDC via the CCTP Bridge](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/) From b92ec39e17bd5cf878ef85aa3dc3c895f7887043 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 11:48:46 -0400 Subject: [PATCH 45/55] update llms --- llms-files/llms-basics.txt | 38 ++-- llms-files/llms-connect.txt | 112 +++++----- llms-files/llms-multigov.txt | 82 ++++---- llms-files/llms-ntt.txt | 116 +++++----- llms-files/llms-queries.txt | 72 +++---- llms-files/llms-relayers.txt | 38 ++-- llms-files/llms-settlement.txt | 52 ++--- llms-files/llms-solidity-sdk.txt | 38 ++-- llms-files/llms-token-bridge.txt | 84 ++++---- llms-files/llms-transfer.txt | 242 ++++++++++----------- llms-files/llms-typescript-sdk.txt | 38 ++-- llms-full.txt | 328 ++++++++++++++--------------- 12 files changed, 620 insertions(+), 620 deletions(-) diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index a9de0e5e4..9a75e8ddd 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -927,18 +927,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -948,29 +948,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -1642,7 +1642,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index 443cbbdc6..694414ad7 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -413,18 +413,18 @@ By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wr The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank}: Manually redeemed Wormhole Token Bridge route. +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank}: Automatically redeemed (relayed) Token Bridge route. +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank}: Manually redeemed CCTP route. +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank}: Automatically redeemed (relayed) CCTP route. +- **`DEFAULT_ROUTES`**: Array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`). +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank}: Function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route. +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}: Function that returns the manually-redeemed NTT route. +- **`nttRoutes(nttConfig)`**: Function that returns both NTT routes as an array. +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank}: Route that offers multiple Mayan protocols. +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank}: Route for Mayan's Swift protocol only. +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank}: Route for Mayan's MCTP protocol only. +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank}: Route for Mayan's original Wormhole transfer protocol. In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. @@ -685,7 +685,7 @@ categories: Connect, Transfer ## Theme & UI Customization -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +This page focuses on how to style the Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. ### Changing the Color Scheme @@ -968,10 +968,10 @@ export default App; The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: -- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` -- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains -- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI -- **Defines the theme** - this example sets the mode to `dark` and adds a primary color +- **Defines the network**: Options include `Mainnet`, `Testnet`, or `Devnet`. +- **Defines chains to include**: This example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains. +- **Adds a title to UI**: (Optional) If defined, it will render above the widget in the UI. +- **Defines the theme**: This example sets the mode to `dark` and adds a primary color. ## Interact with Connect @@ -1006,7 +1006,7 @@ If you're using React, refer to the [Get Started with Connect](/docs/products/co ## Install Connect -To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: +To install the [Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: ```bash npm i @wormhole-foundation/wormhole-connect @@ -1087,7 +1087,7 @@ These updates ensure better performance and a smoother integration experience. ## Update the Connect Package -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +To begin the migration process, update the Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. Run the following command in your terminal: @@ -1190,11 +1190,11 @@ The `networks` property, which allowed whitelisting chains, is now renamed `chai ### Update `routes` to Use Route Plugins -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +The `routes` property in Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: +By default, if no `routes` property is set, Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -1204,7 +1204,7 @@ For most use cases, integrators require more than the default routes. The new `r The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: ???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`TokenBridgeRoute`** - manually redeemed Token Bridge route - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - **`CCTPRoute`** - manually redeemed CCTP route - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route @@ -1225,7 +1225,7 @@ Now that you know the available `route` plugins, let's explore some examples of #### Example: Offer Only CCTP Transfers -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +To configure Connect to offer only USDC transfers via the CCTP route, use the following configuration: ```typescript import WormholeConnect, { @@ -1242,7 +1242,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -1265,7 +1265,7 @@ This flexible plugin allows you to combine default routes (such as Token Bridge ### Update the `tokensConfig` Structure -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +In Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. Key Changes to `tokensConfig`: @@ -1342,7 +1342,7 @@ Key Changes to `tokensConfig`: ### Update NTT Configuration -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +In Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. Key changes: @@ -1441,7 +1441,7 @@ This change simplifies the configuration process by providing a cleaner, more fl ### Update UI Configuration -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. +In Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. Key UI changes: @@ -1565,7 +1565,7 @@ Important details: ### Removed Configuration Properties -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. +Several configuration properties have been removed in Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. Removed config keys: @@ -1593,7 +1593,7 @@ For those using the CDN-hosted version of Wormhole Connect, the package's instal npm install @wormhole-foundation/wormhole-connect@^1.0 ``` -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: +2. After installing the package, you can embed Connect into your page by adding the following code: ```typescript import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; @@ -1678,19 +1678,19 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + - [**Connect**](/docs/products/connect/get-started/): Handles user-friendly asset transfers. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Moves native assets across chains. + - [**Queries**](/docs/products/queries/overview/): Fetches real-time prices for optimal trade execution. - **Cross-Chain Payment Widgets** - - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/get-started/): Facilitates seamless payments in various tokens. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Ensures direct, native asset transfers. - **Web3 Game Asset Transfers** - - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains - - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/get-started/): Provide a user-friendly way to move game tokens across chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/): Handle the underlying lock-and-mint logic securely. ## Next Steps @@ -2703,18 +2703,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -2724,29 +2724,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -3418,7 +3418,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 9da345919..adae33b10 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -531,8 +531,8 @@ MultiGov deployments follow a similar structure on both EVM and Solana. This sec You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: - - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains - - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank}: Configure and deploy MultiGov smart contracts to EVM-compatible chains. + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank}: Launch the Solana staking program and configure spoke chain participation. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ @@ -988,21 +988,21 @@ MultiGov is a multichain governance system that enables decentralized decision-m MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: -- **Multichain governance** – token holders can vote and execute proposals from any supported chain -- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live -- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain -- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity -- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} +- **Multichain governance**: Token holders can vote and execute proposals from any supported chain. +- **Hub-and-spoke model**: Proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live. +- **Secure vote aggregation**: Vote weights are checkpointed and verified to prevent double voting. +- **Cross-chain proposal execution**: Approved proposals can be executed across multiple chains. +- **Flexible architecture**: Can integrate with any Wormhole-supported blockchain. +- **Upgradeable and extensible**: Supports upgrades across components while preserving vote history and system continuity. +- **Backed by Tally**: Proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank}. ## How It Works -1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling -2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power -3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification -4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends -5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands +1. **Create proposal on hub chain**: Proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling. +2. **Vote from spoke chains**: Token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power. +3. **Transmit votes via Wormhole**: Votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification. +4. **Aggregate and finalize on hub**: The hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends. +5. **Execute actions across chains**: Upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands. @@ -1010,20 +1010,20 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Vote on treasury actions from any supported chain. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Transmit proposal execution to target chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Optionally move assets. - **Coordinated Protocol Upgrades Across Chains** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Create a unified proposal to upgrade contracts across networks. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Send upgrade instructions as VAAs and deliver execution payloads to target chains. - **Progressive Decentralization for Multichain DAOs** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Extend governance to new chains while preserving coordination. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch on-chain vote weights from remote spokes. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Aggregate results and execute actions via the hub. ## Next Steps @@ -1949,18 +1949,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -1970,29 +1970,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -2664,7 +2664,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 04d2e6bcb..0effe95a6 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -685,8 +685,8 @@ In the deployment steps, you will add your supported chains, their token address You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: -- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank}: Deploy NTT on EVM-compatible chains. +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank}: Deploy NTT on Solana. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ @@ -1232,8 +1232,8 @@ The NTT Launchpad currently supports deployments on the following mainnet chains Once ready, choose an option to proceed: - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token): Deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains. + - [**Expand Your Existing Token**](#expand-your-existing-token): If you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract. ## Launch a Cross-Chain Token @@ -1337,8 +1337,8 @@ Use the drop-down menu at the top to select the chain you want to configure. The From this section, you can also: - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain + - **Pause the token**: Temporarily turn off transfers on the selected chain. + - **Deploy to a new chain**: Expand your token by deploying it to an additional chain. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) @@ -1346,8 +1346,8 @@ From this section, you can also: This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers + - **Manager’s Owner**: The owner through the `NTTOwner` proxy. + - **Pauser**: The address authorized to pause transfers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) @@ -1357,8 +1357,8 @@ Determine and update how transceivers interact with the token. [Transceivers](/d A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + - **Registered Transceivers**: Displays the number of registered transceivers and their addresses. + - **Transceivers Threshold**: A configurable value that must be less than or equal to the number of transceivers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) @@ -1366,8 +1366,8 @@ A higher transceiver threshold increases security by requiring more approvals be Define the transfer restrictions for each connected network. You can adjust: - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + - **Sending Limits**: The maximum amount of tokens that can be sent from the home chain. + - **Receiving Limits**: The maximum amount of tokens that can be received for each of the supported peer chains. Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. @@ -1388,7 +1388,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Consider a streamlined, customizable frontend such as [Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -1407,7 +1407,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Connect, a customizable widget for cross-chain asset transfers. [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) @@ -1545,18 +1545,18 @@ Native Token Transfers (NTT) provides an adaptable framework for transferring yo ## Key Features -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +- **Control and customization**: Ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls. +- **Advanced rate limiting**: Set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments. +- **Global accountant**: Ensures the amount burned and transferred on chains never exceeds the amount of tokens minted. +- **No wrapped tokens**: Tokens are used directly within their native ecosystem, eliminating intermediary transfer steps. ## Deployment Models NTT offers two operational modes for your existing tokens: -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token +- **Hub-and-spoke**: Locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts. +- **Burn-and-mint**: Burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token. ## Supported Token Standards @@ -1570,42 +1570,42 @@ NTT does not currently support token standards like ERC-721 (non-fungible tokens Here's a breakdown of the key steps involved when deploying NTT: -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed +- **Prepare tokens**: Ensure your ERC-20 or SPL tokens are ready. +- **Choose deployment model**: Choose your cross-chain token model: either burn-and-mint or hub-and-spoke. +- **Choose deployment tool**: Use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank}. +- **Initialization**: Specify target chains and token details, and set up your CLI environment if using it. +- **Deploy contracts**: Deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees. +- **Finalize configurations**: Grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles. +- **Monitor and maintain**: Verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed. ## Use Cases - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transmits native assets across chains. + - [**Connect**](/docs/products/connect/overview/): Manages user-friendly asset transfers. + - [**Queries**](/docs/products/queries/overview/): Acquires real-time prices for optimal trade execution. - **Borrowing and Lending Across Chains** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Moves collateral as native assets. + - [**Messaging**](/docs/products/messaging/overview/): Propagates loan requests and liquidations across chains. + - [**Queries**](/docs/products/queries/overview/): Retrieves interest rates and asset prices in real-time. - **Gas Abstraction** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Facilitates native token conversion for gas payments. + - [**Messaging**](/docs/products/messaging/overview/): Sends gas fee payments across chains. - **Cross-Chain Payment Widgets** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Ensures direct, native asset transfers. + - [**Connect**](/docs/products/connect/overview/): Facilitates seamless payments in various tokens. - **Cross-Chain Staking** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transfers staked assets natively between networks. + - [**Messaging**](/docs/products/messaging/overview/): Moves staking rewards and governance signals across chains. ## Next Steps @@ -2905,18 +2905,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -2926,29 +2926,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -3620,7 +3620,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index f319a8d4e..1f1c138e3 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -643,11 +643,11 @@ Queries provide on-demand access to Guardian-attested on-chain data. They allow ## Key Features -- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time -- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation -- **Cross-chain ready** – request data on one chain, use it on another -- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts -- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} +- **On-demand data access**: Fetch price feeds, interest rates, and other data in real-time. +- **Guardian attested**: All data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation. +- **Cross-chain ready**: Request data on one chain, use it on another. +- **Smart contract integration**: Results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts. +- **Chain agnostic**: works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank}. ## How It Works @@ -669,30 +669,30 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch rates and prices in real-time. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Sync actions between chains. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution - - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch live prices optimal trade execution. + - [**Connect**](/docs/products/connect/overview/){target=\_blank}: Handle user-friendly asset transfers. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Moves native tokens. - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch price feeds. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Trigger trades. - **Multichain Prediction Markets** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch market data and odds. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Automates token execution. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Source data from chains. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Ensures tamper-proof data relay across networks. ## Next Steps @@ -1717,18 +1717,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -1738,29 +1738,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -2432,7 +2432,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index b8496b20d..af7648804 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -1468,18 +1468,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -1489,29 +1489,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -2183,7 +2183,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 6e8db1b6a..310adf48d 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -406,7 +406,7 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: -- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. - [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- @@ -849,18 +849,18 @@ To read more about each protocol, check the [architecture documentation](/docs/p - **Cross-Chain Perpetuals** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Provides fast token execution across chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch live prices and manage position state across chains. - **Bridging Intent Library** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Handles user-defined bridge intents. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Triggers cross-chain function calls. - **Multichain Prediction Markets** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Executes token flows between chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Gets market data and tracks state. ## Next Steps @@ -1788,18 +1788,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -1809,29 +1809,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -2503,7 +2503,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 6d2835cb0..e8f65f654 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -2521,18 +2521,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -2542,29 +2542,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -3236,7 +3236,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index abbc6144a..1408abfdc 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -561,8 +561,8 @@ Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - - **Manual transfer** – where you control each step - - **Automatic transfer** – where a relayer finalizes the transfer for you + - **Manual transfer**: Where you control each step. + - **Automatic transfer**: Where a relayer finalizes the transfer for you. These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. @@ -833,8 +833,8 @@ To verify the transaction and view its details, copy the transaction hash from t Now that you've completed a manual multichain token transfer, explore these guides to continue building: - - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) - - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank}: Build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic). + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank}: Learn how to issue tokens that work across chains. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/token-bridge-contracts/ @@ -1077,21 +1077,21 @@ This overview covers Token Bridge's main features, general processes, and possib Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +- **Interoperability**: Transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank}. +- **Lock-and-mint mechanism**: Mint wrapped tokens backed 1:1 by locked assets on the source chain. +- **Preserved metadata**: Ensure that token properties like name, symbol, and decimals persist across chains. +- **Transfer with payload**: Attach arbitrary data to token transfers, enabling the triggering of specific actions. +- **Decentralized security**: Verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity. ## How It Works The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +1. **Attestation**: The token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token. +2. **Locking**: On the source chain, the native token is locked in a custody account. +3. **Message emission**: The [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +4. **Verification**: The VAA is submitted and verified on the destination chain to confirm authenticity. +5. **Minting**: A wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain. This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. @@ -1120,26 +1120,26 @@ Here are key use cases that highlight the power and versatility of the Token Bri - **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Transfer tokens between chains. + - [**Messaging**](/docs/products/messaging/overview/): Facilitate the distribution and claiming processes of rewards. - **Tokenized Gaming Rewards** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Handle the underlying lock-and-mint logic securely. + - [**Connect**](/docs/products/connect/overview/): Provide a user-friendly way to move game tokens across chains. - **Multichain DeFi Arbitrage** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Enables rapid and secure movement of DeFi assets. + - [**Connect**](/docs/products/connect/overview/): Provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms. ## Next Steps If you are looking for more guided practice, take a look at: -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/): Perform token transfers using the Token Bridge, including manual and automatic transfers. +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/): Build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains. +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/): Craft a multichain token using Wormhole's Portal Bridge. --- END CONTENT --- ## Basics Concepts [shared: true] @@ -2059,18 +2059,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -2080,29 +2080,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -2774,7 +2774,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index c272b869d..dcfb63003 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -3366,18 +3366,18 @@ By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wr The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank}: Manually redeemed Wormhole Token Bridge route. +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank}: Automatically redeemed (relayed) Token Bridge route. +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank}: Manually redeemed CCTP route. +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank}: Automatically redeemed (relayed) CCTP route. +- **`DEFAULT_ROUTES`**: Array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`). +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank}: Function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route. +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}: Function that returns the manually-redeemed NTT route. +- **`nttRoutes(nttConfig)`**: Function that returns both NTT routes as an array. +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank}: Route that offers multiple Mayan protocols. +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank}: Route for Mayan's Swift protocol only. +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank}: Route for Mayan's MCTP protocol only. +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank}: Route for Mayan's original Wormhole transfer protocol. In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. @@ -3638,7 +3638,7 @@ categories: Connect, Transfer ## Theme & UI Customization -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +This page focuses on how to style the Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. ### Changing the Color Scheme @@ -3921,10 +3921,10 @@ export default App; The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: -- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` -- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains -- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI -- **Defines the theme** - this example sets the mode to `dark` and adds a primary color +- **Defines the network**: Options include `Mainnet`, `Testnet`, or `Devnet`. +- **Defines chains to include**: This example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains. +- **Adds a title to UI**: (Optional) If defined, it will render above the widget in the UI. +- **Defines the theme**: This example sets the mode to `dark` and adds a primary color. ## Interact with Connect @@ -3959,7 +3959,7 @@ If you're using React, refer to the [Get Started with Connect](/docs/products/co ## Install Connect -To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: +To install the [Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: ```bash npm i @wormhole-foundation/wormhole-connect @@ -4040,7 +4040,7 @@ These updates ensure better performance and a smoother integration experience. ## Update the Connect Package -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +To begin the migration process, update the Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. Run the following command in your terminal: @@ -4143,11 +4143,11 @@ The `networks` property, which allowed whitelisting chains, is now renamed `chai ### Update `routes` to Use Route Plugins -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +The `routes` property in Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: +By default, if no `routes` property is set, Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -4157,7 +4157,7 @@ For most use cases, integrators require more than the default routes. The new `r The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: ???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`TokenBridgeRoute`** - manually redeemed Token Bridge route - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - **`CCTPRoute`** - manually redeemed CCTP route - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route @@ -4178,7 +4178,7 @@ Now that you know the available `route` plugins, let's explore some examples of #### Example: Offer Only CCTP Transfers -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +To configure Connect to offer only USDC transfers via the CCTP route, use the following configuration: ```typescript import WormholeConnect, { @@ -4195,7 +4195,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -4218,7 +4218,7 @@ This flexible plugin allows you to combine default routes (such as Token Bridge ### Update the `tokensConfig` Structure -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +In Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. Key Changes to `tokensConfig`: @@ -4295,7 +4295,7 @@ Key Changes to `tokensConfig`: ### Update NTT Configuration -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +In Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. Key changes: @@ -4394,7 +4394,7 @@ This change simplifies the configuration process by providing a cleaner, more fl ### Update UI Configuration -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. +In Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. Key UI changes: @@ -4518,7 +4518,7 @@ Important details: ### Removed Configuration Properties -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. +Several configuration properties have been removed in Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. Removed config keys: @@ -4546,7 +4546,7 @@ For those using the CDN-hosted version of Wormhole Connect, the package's instal npm install @wormhole-foundation/wormhole-connect@^1.0 ``` -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: +2. After installing the package, you can embed Connect into your page by adding the following code: ```typescript import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; @@ -4631,19 +4631,19 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + - [**Connect**](/docs/products/connect/get-started/): Handles user-friendly asset transfers. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Moves native assets across chains. + - [**Queries**](/docs/products/queries/overview/): Fetches real-time prices for optimal trade execution. - **Cross-Chain Payment Widgets** - - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/get-started/): Facilitates seamless payments in various tokens. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Ensures direct, native asset transfers. - **Web3 Game Asset Transfers** - - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains - - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/get-started/): Provide a user-friendly way to move game tokens across chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/): Handle the underlying lock-and-mint logic securely. ## Next Steps @@ -5394,8 +5394,8 @@ In the deployment steps, you will add your supported chains, their token address You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: -- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank}: Deploy NTT on EVM-compatible chains. +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank}: Deploy NTT on Solana. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ @@ -5941,8 +5941,8 @@ The NTT Launchpad currently supports deployments on the following mainnet chains Once ready, choose an option to proceed: - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token): Deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains. + - [**Expand Your Existing Token**](#expand-your-existing-token): If you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract. ## Launch a Cross-Chain Token @@ -6046,8 +6046,8 @@ Use the drop-down menu at the top to select the chain you want to configure. The From this section, you can also: - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain + - **Pause the token**: Temporarily turn off transfers on the selected chain. + - **Deploy to a new chain**: Expand your token by deploying it to an additional chain. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) @@ -6055,8 +6055,8 @@ From this section, you can also: This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers + - **Manager’s Owner**: The owner through the `NTTOwner` proxy. + - **Pauser**: The address authorized to pause transfers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) @@ -6066,8 +6066,8 @@ Determine and update how transceivers interact with the token. [Transceivers](/d A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + - **Registered Transceivers**: Displays the number of registered transceivers and their addresses. + - **Transceivers Threshold**: A configurable value that must be less than or equal to the number of transceivers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) @@ -6075,8 +6075,8 @@ A higher transceiver threshold increases security by requiring more approvals be Define the transfer restrictions for each connected network. You can adjust: - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + - **Sending Limits**: The maximum amount of tokens that can be sent from the home chain. + - **Receiving Limits**: The maximum amount of tokens that can be received for each of the supported peer chains. Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. @@ -6097,7 +6097,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Consider a streamlined, customizable frontend such as [Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -6116,7 +6116,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Connect, a customizable widget for cross-chain asset transfers. [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) @@ -6254,18 +6254,18 @@ Native Token Transfers (NTT) provides an adaptable framework for transferring yo ## Key Features -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +- **Control and customization**: Ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls. +- **Advanced rate limiting**: Set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments. +- **Global accountant**: Ensures the amount burned and transferred on chains never exceeds the amount of tokens minted. +- **No wrapped tokens**: Tokens are used directly within their native ecosystem, eliminating intermediary transfer steps. ## Deployment Models NTT offers two operational modes for your existing tokens: -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token +- **Hub-and-spoke**: Locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts. +- **Burn-and-mint**: Burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token. ## Supported Token Standards @@ -6279,42 +6279,42 @@ NTT does not currently support token standards like ERC-721 (non-fungible tokens Here's a breakdown of the key steps involved when deploying NTT: -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed +- **Prepare tokens**: Ensure your ERC-20 or SPL tokens are ready. +- **Choose deployment model**: Choose your cross-chain token model: either burn-and-mint or hub-and-spoke. +- **Choose deployment tool**: Use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank}. +- **Initialization**: Specify target chains and token details, and set up your CLI environment if using it. +- **Deploy contracts**: Deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees. +- **Finalize configurations**: Grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles. +- **Monitor and maintain**: Verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed. ## Use Cases - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transmits native assets across chains. + - [**Connect**](/docs/products/connect/overview/): Manages user-friendly asset transfers. + - [**Queries**](/docs/products/queries/overview/): Acquires real-time prices for optimal trade execution. - **Borrowing and Lending Across Chains** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Moves collateral as native assets. + - [**Messaging**](/docs/products/messaging/overview/): Propagates loan requests and liquidations across chains. + - [**Queries**](/docs/products/queries/overview/): Retrieves interest rates and asset prices in real-time. - **Gas Abstraction** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Facilitates native token conversion for gas payments. + - [**Messaging**](/docs/products/messaging/overview/): Sends gas fee payments across chains. - **Cross-Chain Payment Widgets** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Ensures direct, native asset transfers. + - [**Connect**](/docs/products/connect/overview/): Facilitates seamless payments in various tokens. - **Cross-Chain Staking** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transfers staked assets natively between networks. + - [**Messaging**](/docs/products/messaging/overview/): Moves staking rewards and governance signals across chains. ## Next Steps @@ -7149,7 +7149,7 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: -- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. - [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- @@ -7592,18 +7592,18 @@ To read more about each protocol, check the [architecture documentation](/docs/p - **Cross-Chain Perpetuals** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Provides fast token execution across chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch live prices and manage position state across chains. - **Bridging Intent Library** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Handles user-defined bridge intents. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Triggers cross-chain function calls. - **Multichain Prediction Markets** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Executes token flows between chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Gets market data and tracks state. ## Next Steps @@ -8095,21 +8095,21 @@ This overview covers Token Bridge's main features, general processes, and possib Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +- **Interoperability**: Transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank}. +- **Lock-and-mint mechanism**: Mint wrapped tokens backed 1:1 by locked assets on the source chain. +- **Preserved metadata**: Ensure that token properties like name, symbol, and decimals persist across chains. +- **Transfer with payload**: Attach arbitrary data to token transfers, enabling the triggering of specific actions. +- **Decentralized security**: Verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity. ## How It Works The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +1. **Attestation**: The token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token. +2. **Locking**: On the source chain, the native token is locked in a custody account. +3. **Message emission**: The [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +4. **Verification**: The VAA is submitted and verified on the destination chain to confirm authenticity. +5. **Minting**: A wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain. This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. @@ -8138,26 +8138,26 @@ Here are key use cases that highlight the power and versatility of the Token Bri - **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Transfer tokens between chains. + - [**Messaging**](/docs/products/messaging/overview/): Facilitate the distribution and claiming processes of rewards. - **Tokenized Gaming Rewards** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Handle the underlying lock-and-mint logic securely. + - [**Connect**](/docs/products/connect/overview/): Provide a user-friendly way to move game tokens across chains. - **Multichain DeFi Arbitrage** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Enables rapid and secure movement of DeFi assets. + - [**Connect**](/docs/products/connect/overview/): Provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms. ## Next Steps If you are looking for more guided practice, take a look at: -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/): Perform token transfers using the Token Bridge, including manual and automatic transfers. +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/): Build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains. +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/): Craft a multichain token using Wormhole's Portal Bridge. --- END CONTENT --- ## Basics Concepts [shared: true] @@ -9077,18 +9077,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -9098,29 +9098,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -9792,7 +9792,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 04473d949..9e3e3a9aa 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -4762,18 +4762,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -4783,29 +4783,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -5477,7 +5477,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- diff --git a/llms-full.txt b/llms-full.txt index 3e5da64f9..bd6206636 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -4518,18 +4518,18 @@ By default, Connect offers two bridging protocols: Token Bridge (for Wormhole-wr The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: -- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank} - manually redeemed Wormhole Token Bridge route -- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank} - automatically redeemed (relayed) Token Bridge route -- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank} - manually redeemed CCTP route -- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank} - automatically redeemed (relayed) CCTP route -- **`DEFAULT_ROUTES`** - array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`) -- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank} - function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route -- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}- function that returns the manually-redeemed NTT route -- **`nttRoutes(nttConfig)`** - function that returns both NTT routes as an array -- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank} - route that offers multiple Mayan protocols -- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank} - route for Mayan's Swift protocol only -- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank} - route for Mayan's MCTP protocol only -- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank} - route for Mayan's original Wormhole transfer protocol +- [**`TokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\_blank}: Manually redeemed Wormhole Token Bridge route. +- [**`AutomaticTokenBridgeRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/automatic.ts){target=\_blank}: Automatically redeemed (relayed) Token Bridge route. +- [**`CCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\_blank}: Manually redeemed CCTP route. +- [**`AutomaticCCTPRoute`**](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\_blank}: Automatically redeemed (relayed) CCTP route. +- **`DEFAULT_ROUTES`**: Array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`). +- [**`nttAutomaticRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/automatic.ts){target=\_blank}: Function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route. +- [**`nttManualRoute(nttConfig)`**](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/route/src/manual.ts){target=\_blank}: Function that returns the manually-redeemed NTT route. +- **`nttRoutes(nttConfig)`**: Function that returns both NTT routes as an array. +- [**`MayanRoute`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\_blank}: Route that offers multiple Mayan protocols. +- [**`MayanRouteSWIFT`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\_blank}: Route for Mayan's Swift protocol only. +- [**`MayanRouteMCTP`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\_blank}: Route for Mayan's MCTP protocol only. +- [**`MayanRouteWH`**](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L550){target=\_blank}: Route for Mayan's original Wormhole transfer protocol. In addition to these routes, developers can create custom routes for their Wormhole-based protocols. For examples, refer to the [NTT](https://github.com/wormhole-foundation/native-token-transfers/tree/main/sdk/route){target=\_blank} and the [Mayan](https://github.com/mayan-finance/wormhole-sdk-route){target=\_blank} example GitHub repositories. @@ -4790,7 +4790,7 @@ categories: Connect, Transfer ## Theme & UI Customization -This page focuses on how to style the Wormhole Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. +This page focuses on how to style the Connect widget, covering color schemes, fonts, layout changes (like toggling the hamburger menu), and adding extra menu entries. You'll learn how to customize Connect's look and feel to match your application's branding. ### Changing the Color Scheme @@ -5073,10 +5073,10 @@ export default App; The preceding sample code configures Connect by setting values inside `config` and `theme` as follows: -- **Defines the network** - options include `Mainnet`, `Testnet`, or `Devnet` -- **Defines chains to include** - this example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains -- **Adds a title to UI** - (optional) if defined, it will render above the widget in the UI -- **Defines the theme** - this example sets the mode to `dark` and adds a primary color +- **Defines the network**: Options include `Mainnet`, `Testnet`, or `Devnet`. +- **Defines chains to include**: This example uses Sui and Avalanche. See the complete list of [Connect-supported chain names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts){target=\_blank} if you would like to use different chains. +- **Adds a title to UI**: (Optional) If defined, it will render above the widget in the UI. +- **Defines the theme**: This example sets the mode to `dark` and adds a primary color. ## Interact with Connect @@ -5111,7 +5111,7 @@ If you're using React, refer to the [Get Started with Connect](/docs/products/co ## Install Connect -To install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: +To install the [Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\_blank}, run the following command: ```bash npm i @wormhole-foundation/wormhole-connect @@ -5192,7 +5192,7 @@ These updates ensure better performance and a smoother integration experience. ## Update the Connect Package -To begin the migration process, update the Wormhole Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. +To begin the migration process, update the Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect/v/1.0.0-beta.6-development?activeTab=readme){target=\_blank} to the latest version 1.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities. Run the following command in your terminal: @@ -5295,11 +5295,11 @@ The `networks` property, which allowed whitelisting chains, is now renamed `chai ### Update `routes` to Use Route Plugins -The `routes` property in Wormhole Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. +The `routes` property in Connect version 1.0 has significantly improved. Previously, `routes` was a simple array of strings. The latest version has been transformed into a flexible plugin system, allowing you to include specific routes for various protocols. -By default, if no `routes` property is set, Wormhole Connect will provide routes for two core protocols: +By default, if no `routes` property is set, Connect will provide routes for two core protocols: - - [Wormhole Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} + - [Token Bridge](/docs/products/token-bridge/overview/){target=\_blank} - [CCTP](/docs/products/cctp-bridge/overview/){target=\_blank} For most use cases, integrators require more than the default routes. The new `routes` property allows you to specify which protocols to include and exclude any routes unnecessary for your application, including both default and third-party routes. @@ -5309,7 +5309,7 @@ For most use cases, integrators require more than the default routes. The new `r The `@wormhole-foundation/wormhole-connect` package offers a variety of `route` plugins to give you flexibility in handling different protocols. You can choose from the following `route` exports for your integration: ???- tip "`route` Plugins" - - **`TokenBridgeRoute`** - manually redeemed Wormhole Token Bridge route + - **`TokenBridgeRoute`** - manually redeemed Token Bridge route - **`AutomaticTokenBridgeRoute`** - automatically redeemed (relayed) Token Bridge route - **`CCTPRoute`** - manually redeemed CCTP route - **`AutomaticCCTPRoute`** - automatically redeemed (relayed) CCTP route @@ -5330,7 +5330,7 @@ Now that you know the available `route` plugins, let's explore some examples of #### Example: Offer Only CCTP Transfers -To configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration: +To configure Connect to offer only USDC transfers via the CCTP route, use the following configuration: ```typescript import WormholeConnect, { @@ -5347,7 +5347,7 @@ const config: WormholeConnectConfig = { #### Example: Offer All Default Routes and Third-Party Plugins -In this example, Wormhole Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. +In this example, Connect is configured with routes for both default protocols (Token Bridge & CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/native-token-transfers/overview/){target=\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\_blank}. ```typescript import WormholeConnect, { @@ -5370,7 +5370,7 @@ This flexible plugin allows you to combine default routes (such as Token Bridge ### Update the `tokensConfig` Structure -In Wormhole Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. +In Connect version 1.0, the `tokensConfig` property has been updated to simplify the structure and improve flexibility for token handling across chains. The previous configuration has been streamlined, and a new key, `wrappedTokens,` has been introduced to handle foreign assets more effectively. Key Changes to `tokensConfig`: @@ -5447,7 +5447,7 @@ Key Changes to `tokensConfig`: ### Update NTT Configuration -In Wormhole Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. +In Connect version 1.0, the `nttGroups` property, which was used to configure Native Token Transfers (NTT), has been removed. Instead, the NTT configuration is passed directly to the NTT route constructor. This update simplifies the setup and provides more flexibility for defining NTT routes. Key changes: @@ -5546,7 +5546,7 @@ This change simplifies the configuration process by providing a cleaner, more fl ### Update UI Configuration -In Wormhole Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. +In Connect version 1.0, the user interface configuration has been significantly updated. Several previously scattered UI properties have now been consolidated under a new `ui` key, making the UI configuration cleaner and easier to manage. Key UI changes: @@ -5670,7 +5670,7 @@ Important details: ### Removed Configuration Properties -Several configuration properties have been removed in Wormhole Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. +Several configuration properties have been removed in Connect version 1.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes. Removed config keys: @@ -5698,7 +5698,7 @@ For those using the CDN-hosted version of Wormhole Connect, the package's instal npm install @wormhole-foundation/wormhole-connect@^1.0 ``` -2. After installing the package, you can embed Wormhole Connect into your page by adding the following code: +2. After installing the package, you can embed Connect into your page by adding the following code: ```typescript import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect'; @@ -5783,19 +5783,19 @@ Here are some key use cases that highlight the power and versatility of Connect: - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Connect**](/docs/products/connect/get-started/): handles user-friendly asset transfers - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – moves native assets across chains - - [**Queries**](/docs/products/queries/overview/) – fetches real-time prices for optimal trade execution + - [**Connect**](/docs/products/connect/get-started/): Handles user-friendly asset transfers. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Moves native assets across chains. + - [**Queries**](/docs/products/queries/overview/): Fetches real-time prices for optimal trade execution. - **Cross-Chain Payment Widgets** - - [**Connect**](/docs/products/connect/get-started/) – facilitates seamless payments in various tokens - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/) – ensures direct, native asset transfers + - [**Connect**](/docs/products/connect/get-started/): Facilitates seamless payments in various tokens. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/): Ensures direct, native asset transfers. - **Web3 Game Asset Transfers** - - [**Connect**](/docs/products/connect/get-started/) – provide a user-friendly way to move game tokens across chains - - [**Token Bridge**](/docs/products/token-bridge/overview/) – handle the underlying lock-and-mint logic securely + - [**Connect**](/docs/products/connect/get-started/): Provide a user-friendly way to move game tokens across chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/): Handle the underlying lock-and-mint logic securely. ## Next Steps @@ -6979,18 +6979,18 @@ Wormhole Messaging is the core protocol of the Wormhole ecosystem—a generic, m ## Key Features -- **Multichain messaging** - send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems -- **Decentralized validation** - a network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity -- **Composable architecture** - works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases +- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems. +- **Decentralized validation**: A network of independent [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observes and signs multichain messages, producing [Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank} that ensure integrity. +- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases. ## How It Works The messaging flow consists of several core components: -1. **Source chain (emitter contract)** - a contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain -2. **Guardian Network** - [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -3. **Relayers** - off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain -4. **Target chain (recipient contract)** - the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic +1. **Source chain (emitter contract)**: A contract emits a message by calling the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the source chain. +2. **Guardian Network**: [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} observe the message, validate it, and generate a signed [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +3. **Relayers**: Off-chain or on-chain [relayers](/docs/protocol/infrastructure/relayer/){target=\_blank} transport the VAA to the destination chain. +4. **Target chain (recipient contract)**: The [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\_blank} on the destination chain verifies the VAA and triggers the specified application logic. ![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp) @@ -7000,29 +7000,29 @@ Wormhole Messaging enables a wide range of multichain applications. Below are co - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate actions across chains - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch rates and prices in real-time + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate actions across chains. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch rates and prices in real-time. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – relay verified data - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – aggregate multi-chain sources + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Relay verified data. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Aggregate multi-chain sources. - **Gas Abstraction** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – coordinate gas logic - - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank} – handle native token swaps + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Coordinate gas logic. + - [**Native Token Transfers**](/docs/products/native-token-transfers/overview/){target=\_blank}: Handle native token swaps. - **Bridging Intent Library** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – dispatch and execute intents - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} - execute user-defined bridging intents + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Dispatch and execute intents. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Execute user-defined bridging intents. - **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank} – facilitate decentralized interactions - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – enable tokenized rewards + - [**Messaging**](/docs/products/messaging/get-started/){target=\_blank}: Facilitate decentralized interactions. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Enable tokenized rewards. ## Next Steps @@ -10958,8 +10958,8 @@ MultiGov deployments follow a similar structure on both EVM and Solana. This sec You've now completed the initial setup and requested access through Tally. Continue to the deployment guide that matches your governance architecture: - - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank} – configure and deploy MultiGov smart contracts to EVM-compatible chains - - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank} – launch the Solana staking program and configure spoke chain participation + - [**Deploy on EVM Chains**](/docs/products/multigov/guides/deploy-to-evm){target=\_blank}: Configure and deploy MultiGov smart contracts to EVM-compatible chains. + - [**Deploy on Solana**](/docs/products/multigov/guides/deploy-to-solana){target=\_blank}: Launch the Solana staking program and configure spoke chain participation. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/multigov/guides/deploy-to-evm/ @@ -11415,21 +11415,21 @@ MultiGov is a multichain governance system that enables decentralized decision-m MultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include: -- **Multichain governance** – token holders can vote and execute proposals from any supported chain -- **Hub-and-spoke model** - proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live -- **Secure vote aggregation** - vote weights are checkpointed and verified to prevent double voting -- **Cross-chain proposal execution** - approved proposals can be executed across multiple chains -- **Flexible architecture** - can integrate with any Wormhole-supported blockchain -- **Upgradeable and extensible** – supports upgrades across components while preserving vote history and system continuity -- **Backed by Tally** – proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank} +- **Multichain governance**: Token holders can vote and execute proposals from any supported chain. +- **Hub-and-spoke model**: Proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live. +- **Secure vote aggregation**: Vote weights are checkpointed and verified to prevent double voting. +- **Cross-chain proposal execution**: Approved proposals can be executed across multiple chains. +- **Flexible architecture**: Can integrate with any Wormhole-supported blockchain. +- **Upgradeable and extensible**: Supports upgrades across components while preserving vote history and system continuity. +- **Backed by Tally**: Proposal creation, voting, and execution are coordinated via [Tally](https://www.tally.xyz/get-started){target=\_blank}. ## How It Works -1. **Create proposal on hub chain** - proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling -2. **Vote from spoke chains** - token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power -3. **Transmit votes via Wormhole** - votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification -4. **Aggregate and finalize on hub** - the hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends -5. **Execute actions across chains** - upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands +1. **Create proposal on hub chain**: Proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling. +2. **Vote from spoke chains**: Token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power. +3. **Transmit votes via Wormhole**: Votes are securely sent to the hub using [VAAs](/docs/protocol/infrastructure/vaas/){target=\_blank}, ensuring message integrity and cross-chain verification. +4. **Aggregate and finalize on hub**: The hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends. +5. **Execute actions across chains**: Upon approval, proposals can trigger execution on one or more chains, again using [Wormhole messaging](/docs/products/messaging/overview/){target=\_blank} to deliver commands. @@ -11437,20 +11437,20 @@ MultiGov expands DAO governance across blockchains, increasing participation, im - **Cross-Chain Treasury Management** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – vote on treasury actions from any supported chain - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – transmit proposal execution to target chains - - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank} – optionally move assets + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Vote on treasury actions from any supported chain. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Transmit proposal execution to target chains. + - [**Token Bridge**](/docs/products/token-bridge/overview/){target=\_blank}: Optionally move assets. - **Coordinated Protocol Upgrades Across Chains** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – create a unified proposal to upgrade contracts across networks - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – send upgrade instructions as VAAs and deliver execution payloads to target chains + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Create a unified proposal to upgrade contracts across networks. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Send upgrade instructions as VAAs and deliver execution payloads to target chains. - **Progressive Decentralization for Multichain DAOs** - - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank} – extend governance to new chains while preserving coordination - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch on-chain vote weights from remote spokes - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – aggregate results and execute actions via the hub + - [**MultiGov**](/docs/products/multigov/get-started/){target=\_blank}: Extend governance to new chains while preserving coordination. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch on-chain vote weights from remote spokes. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Aggregate results and execute actions via the hub. ## Next Steps @@ -12331,8 +12331,8 @@ In the deployment steps, you will add your supported chains, their token address You have scaffolded your NTT project and initialized the configuration file. Next, follow the appropriate guide below to configure your supported chains and deploy NTT contracts: -- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank} -- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank} +- [Deploy to EVM](/docs/products/native-token-transfers/guides/deploy-to-evm/){target=\_blank}: Deploy NTT on EVM-compatible chains. +- [Deploy to Solana](/docs/products/native-token-transfers/guides/deploy-to-solana/){target=\_blank}: Deploy NTT on Solana. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/native-token-transfers/guides/deploy-to-evm/ @@ -12878,8 +12878,8 @@ The NTT Launchpad currently supports deployments on the following mainnet chains Once ready, choose an option to proceed: - - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token) - deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains - - [**Expand Your Existing Token**](#expand-your-existing-token) - if you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract + - [**Launch a Cross-Chain Token**](#launch-a-cross-chain-token): Deploy a brand-new token that is NTT-ready from day one, enabling seamless transfers across multiple blockchains. + - [**Expand Your Existing Token**](#expand-your-existing-token): If you already have a token deployed on different chains, integrate it with NTT to enable NTT without modifying its original contract. ## Launch a Cross-Chain Token @@ -12983,8 +12983,8 @@ Use the drop-down menu at the top to select the chain you want to configure. The From this section, you can also: - - **Pause the token** – temporarily turn off transfers on the selected chain - - **Deploy to a new chain** – expand your token by deploying it to an additional chain + - **Pause the token**: Temporarily turn off transfers on the selected chain. + - **Deploy to a new chain**: Expand your token by deploying it to an additional chain. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp) @@ -12992,8 +12992,8 @@ From this section, you can also: This section displays key [roles](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} involved in token governance. You can view and modify these roles by selecting a new address and confirming the update. - - **Manager’s Owner** – the owner through the `NTTOwner` proxy - - **Pauser** – the address authorized to pause transfers + - **Manager’s Owner**: The owner through the `NTTOwner` proxy. + - **Pauser**: The address authorized to pause transfers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp) @@ -13003,8 +13003,8 @@ Determine and update how transceivers interact with the token. [Transceivers](/d A higher transceiver threshold increases security by requiring more approvals before processing a transfer, but it may also slow down transactions. A lower threshold allows faster transfers but reduces redundancy in message verification. - - **Registered Transceivers** – displays the number of registered transceivers and their addresses - - **Transceivers Threshold** – a configurable value that must be less than or equal to the number of transceivers + - **Registered Transceivers**: Displays the number of registered transceivers and their addresses. + - **Transceivers Threshold**: A configurable value that must be less than or equal to the number of transceivers. ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp) @@ -13012,8 +13012,8 @@ A higher transceiver threshold increases security by requiring more approvals be Define the transfer restrictions for each connected network. You can adjust: - - **Sending Limits** – the maximum amount of tokens that can be sent from the home chain - - **Receiving Limits** – the maximum amount of tokens that can be received for each of the supported peer chains + - **Sending Limits**: The maximum amount of tokens that can be sent from the home chain. + - **Receiving Limits**: The maximum amount of tokens that can be received for each of the supported peer chains. Enter a new value to adjust limits and click **Update**. The changes will take effect immediately. @@ -13034,7 +13034,7 @@ To offer the best user experience and ensure the most robust deployment, Wormhol - Implement a robust testing plan for your multichain token before launching - Ensure comprehensive, documented security measures are followed for custody of contract ownership, control of keys, and access control roles. Check the [NTT configuration](/docs/products/native-token-transfers/configuration/access-control/){target=\_blank} for more details on ownership and rate limits -- Consider a streamlined, customizable frontend such as [Wormhole Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience +- Consider a streamlined, customizable frontend such as [Connect](/docs/products/connect/overview/){target=\_blank} for an optimized user experience - Alternatively, the [Wormhole TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank} allows for a direct integration into your infrastructure - Ensure ecosystem actors such as block explorers, automated security tools (such as BlockAid and Blowfish), and wallets (such as MetaMask, Backpack, and Phantom) are aware of your multichain deployment and that it is labeled appropriately - Monitor and maintain your multichain deployment @@ -13053,7 +13053,7 @@ This step ensures that tokens are properly minted or unlocked on Solana and prev --- - Check out an example project that uses a Vite-React TypeScript application and integrates it with Wormhole Connect, a customizable widget for cross-chain asset transfers. + Check out an example project that uses a Vite-React TypeScript application and integrates it with Connect, a customizable widget for cross-chain asset transfers. [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect) @@ -13191,18 +13191,18 @@ Native Token Transfers (NTT) provides an adaptable framework for transferring yo ## Key Features -- **Control and customization** - ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls -- **Advanced rate limiting** - set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments -- **Global accountant** - ensures the amount burned and transferred on chains never exceeds the amount of tokens minted -- **No wrapped tokens** - tokens are used directly within their native ecosystem, eliminating intermediary transfer steps +- **Control and customization**: Ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls. +- **Advanced rate limiting**: Set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments. +- **Global accountant**: Ensures the amount burned and transferred on chains never exceeds the amount of tokens minted. +- **No wrapped tokens**: Tokens are used directly within their native ecosystem, eliminating intermediary transfer steps. ## Deployment Models NTT offers two operational modes for your existing tokens: -- **Hub-and-spoke** - locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts -- **Burn-and-mint** - burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token +- **Hub-and-spoke**: Locks tokens on a central "hub" chain and mints equivalents on "spoke" chains, maintaining the total supply on the hub. It's ideal for integrating existing tokens onto new blockchains without altering their original contracts. +- **Burn-and-mint**: Burns tokens on the source chain and mints new ones on the destination, distributing the total supply across multiple chains. It's best suited for new token deployments or projects willing to upgrade existing contracts for a truly native multichain token. ## Supported Token Standards @@ -13216,42 +13216,42 @@ NTT does not currently support token standards like ERC-721 (non-fungible tokens Here's a breakdown of the key steps involved when deploying NTT: -- **Prepare tokens** - ensure your ERC-20 or SPL tokens are ready -- **Choose deployment model** - choose your cross-chain token model: either burn-and-mint or hub-and-spoke -- **Choose deployment tool** - use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank} -- **Initialization** - specify target chains and token details, and set up your CLI environment if using it -- **Deploy contracts** - deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees -- **Finalize configurations** - grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles -- **Monitor and maintain** - verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed +- **Prepare tokens**: Ensure your ERC-20 or SPL tokens are ready. +- **Choose deployment model**: Choose your cross-chain token model: either burn-and-mint or hub-and-spoke. +- **Choose deployment tool**: Use the [NTT Launchpad](https://ntt.wormhole.com/){target=\_blank} (for EVM chains only) or the [NTT CLI](/docs/products/native-token-transfers/reference/cli-commands/){target=\_blank}. +- **Initialization**: Specify target chains and token details, and set up your CLI environment if using it. +- **Deploy contracts**: Deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees. +- **Finalize configurations**: Grant minting authority, configure rate limits, establish peer manager connections, and assign administrative roles. +- **Monitor and maintain**: Verify deployment, monitor total supply with the [Global Accountant](/docs/products/native-token-transfers/concepts/security/#global-accountant){target=\_blank}, and adjust configurations as needed. ## Use Cases - **Cross-Chain Swaps and Liquidity Aggregation** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transmits native assets across chains - - [**Connect**](/docs/products/connect/overview/) – manages user-friendly asset transfers - - [**Queries**](/docs/products/queries/overview/) – acquires real-time prices for optimal trade execution + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transmits native assets across chains. + - [**Connect**](/docs/products/connect/overview/): Manages user-friendly asset transfers. + - [**Queries**](/docs/products/queries/overview/): Acquires real-time prices for optimal trade execution. - **Borrowing and Lending Across Chains** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – moves collateral as native assets - - [**Messaging**](/docs/products/messaging/overview/) – propagates loan requests and liquidations across chains - - [**Queries**](/docs/products/queries/overview/) – retrieves interest rates and asset prices in real-time + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Moves collateral as native assets. + - [**Messaging**](/docs/products/messaging/overview/): Propagates loan requests and liquidations across chains. + - [**Queries**](/docs/products/queries/overview/): Retrieves interest rates and asset prices in real-time. - **Gas Abstraction** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – facilitates native token conversion for gas payments - - [**Messaging**](/docs/products/messaging/overview/) – sends gas fee payments across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Facilitates native token conversion for gas payments. + - [**Messaging**](/docs/products/messaging/overview/): Sends gas fee payments across chains. - **Cross-Chain Payment Widgets** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – ensures direct, native asset transfers - - [**Connect**](/docs/products/connect/overview/) – facilitates seamless payments in various tokens + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Ensures direct, native asset transfers. + - [**Connect**](/docs/products/connect/overview/): Facilitates seamless payments in various tokens. - **Cross-Chain Staking** - - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/) – transfers staked assets natively between networks - - [**Messaging**](/docs/products/messaging/overview/) – moves staking rewards and governance signals across chains + - [**Native Token Transfers**](/docs/products/native-token-transfers/get-started/): Transfers staked assets natively between networks. + - [**Messaging**](/docs/products/messaging/overview/): Moves staking rewards and governance signals across chains. ## Next Steps @@ -14323,11 +14323,11 @@ Queries provide on-demand access to Guardian-attested on-chain data. They allow ## Key Features -- **On-demand data access** – fetch price feeds, interest rates, and other data in real-time -- **Guardian attested** – all data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation -- **Cross-chain ready** – request data on one chain, use it on another -- **Smart contract integration** – results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts -- **Chain agnostic** – works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank} +- **On-demand data access**: Fetch price feeds, interest rates, and other data in real-time. +- **Guardian attested**: All data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\_blank} for trustless validation. +- **Cross-chain ready**: Request data on one chain, use it on another. +- **Smart contract integration**: Results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\_blank}, readable by smart contracts. +- **Chain agnostic**: works across supported EVM chains, Solana, Sui, and [more](/docs/products/queries/reference/supported-networks/){target=\_blank}. ## How It Works @@ -14349,30 +14349,30 @@ Queries enable a wide range of cross-chain applications. Below are common use ca - **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch rates and prices in real-time - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – sync actions between chains - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – transfer collateral as native assets + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch rates and prices in real-time. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Sync actions between chains. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Transfer collateral as native assets. - **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch live prices optimal trade execution - - [**Connect**](/docs/products/connect/overview/){target=\_blank} – handle user-friendly asset transfers - - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank} – moves native tokens + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch live prices optimal trade execution. + - [**Connect**](/docs/products/connect/overview/){target=\_blank}: Handle user-friendly asset transfers. + - [**Native Token Transfer**](/docs/products/native-token-transfers/overview/){target=\_blank}: Moves native tokens. - **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch price feeds - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – trigger trades + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch price feeds. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Trigger trades. - **Multichain Prediction Markets** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – fetch market data and odds - - [**Settlement**](/docs/products/settlement/overview/){target=\_blank} – automates token execution + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Fetch market data and odds. + - [**Settlement**](/docs/products/settlement/overview/){target=\_blank}: Automates token execution. - **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\_blank})** - - [**Queries**](/docs/products/queries/get-started/){target=\_blank} – source data from chains - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – ensures tamper-proof data relay across networks + - [**Queries**](/docs/products/queries/get-started/){target=\_blank}: Source data from chains. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Ensures tamper-proof data relay across networks. ## Next Steps @@ -15906,7 +15906,7 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: -- Check out the [`demo-mayanswift`](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank} repository for the full code example. +- [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. - [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- @@ -16349,18 +16349,18 @@ To read more about each protocol, check the [architecture documentation](/docs/p - **Cross-Chain Perpetuals** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - fast token execution across chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – fetch live prices and manage position state across chains + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Provides fast token execution across chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Fetch live prices and manage position state across chains. - **Bridging Intent Library** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} - handles user-defined bridge intents - - [**Messaging**](/docs/products/messaging/overview/){target=\_blank} – triggers cross-chain function calls + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Handles user-defined bridge intents. + - [**Messaging**](/docs/products/messaging/overview/){target=\_blank}: Triggers cross-chain function calls. - **Multichain Prediction Markets** - - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank} – executes token flows between chains - - [**Queries**](/docs/products/queries/overview/){target=\_blank} – gets market data and tracks state + - [**Settlement**](/docs/products/settlement/get-started/){target=\_blank}: Executes token flows between chains. + - [**Queries**](/docs/products/queries/overview/){target=\_blank}: Gets market data and tracks state. ## Next Steps @@ -17069,8 +17069,8 @@ Wormhole's [Token Bridge](/docs/products/token-bridge/overview){target=\_blank} In this guide, you will use the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\_blank} to perform two types of transfers. - - **Manual transfer** – where you control each step - - **Automatic transfer** – where a relayer finalizes the transfer for you + - **Manual transfer**: Where you control each step. + - **Automatic transfer**: Where a relayer finalizes the transfer for you. These examples will help you understand how the Token Bridge works across EVM and non-EVM chains. @@ -17341,8 +17341,8 @@ To verify the transaction and view its details, copy the transaction hash from t Now that you've completed a manual multichain token transfer, explore these guides to continue building: - - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank} – build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic) - - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank} – learn how to issue tokens that work across chains + - [Complete Token Transfer Workflow](/docs/products/token-bridge/tutorials/transfer-workflow){target=\_blank}: Build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic). + - [Create Multichain Tokens](/docs/products/token-bridge/tutorials/multichain-token){target=\_blank}: Learn how to issue tokens that work across chains. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/guides/token-bridge-contracts/ @@ -17585,21 +17585,21 @@ This overview covers Token Bridge's main features, general processes, and possib Token Bridge is built to solve interoperability problems in multichain token transfers. Key features include: -- **Interoperability** - transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank} -- **Lock-and-mint mechanism** - mint wrapped tokens backed 1:1 by locked assets on the source chain -- **Preserved metadata** - ensure that token properties like name, symbol, and decimals persist across chains -- **Transfer with payload** - attach arbitrary data to token transfers, enabling the triggering of specific actions -- **Decentralized security** - verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity +- **Interoperability**: Transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#token-bridge){target=\_blank}. +- **Lock-and-mint mechanism**: Mint wrapped tokens backed 1:1 by locked assets on the source chain. +- **Preserved metadata**: Ensure that token properties like name, symbol, and decimals persist across chains. +- **Transfer with payload**: Attach arbitrary data to token transfers, enabling the triggering of specific actions. +- **Decentralized security**: Verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank}, ensuring cross-chain consistency and message authenticity. ## How It Works The Token Bridge provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps: -1. **Attestation** - the token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token -2. **Locking** - on the source chain, the native token is locked in a custody account -3. **Message emission** - the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank} -4. **Verification** - the VAA is submitted and verified on the destination chain to confirm authenticity -5. **Minting** - a wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain +1. **Attestation**: The token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token. +2. **Locking**: On the source chain, the native token is locked in a custody account. +3. **Message emission**: The [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\_blank}. +4. **Verification**: The VAA is submitted and verified on the destination chain to confirm authenticity. +5. **Minting**: A wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain. This diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana. @@ -17628,26 +17628,26 @@ Here are key use cases that highlight the power and versatility of the Token Bri - **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\_blank})** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – transfer tokens between chains - - [**Messaging**](/docs/products/messaging/overview/) – facilitate the distribution and claiming processes of rewards + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Transfer tokens between chains. + - [**Messaging**](/docs/products/messaging/overview/): Facilitate the distribution and claiming processes of rewards. - **Tokenized Gaming Rewards** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – handle the underlying lock-and-mint logic securely - - [**Connect**](/docs/products/connect/overview/) - provide a user-friendly way to move game tokens across chains + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Handle the underlying lock-and-mint logic securely. + - [**Connect**](/docs/products/connect/overview/): Provide a user-friendly way to move game tokens across chains. - **Multichain DeFi Arbitrage** - - [**Token Bridge**](/docs/products/token-bridge/get-started/) – enables rapid and secure movement of DeFi assets - - [**Connect**](/docs/products/connect/overview/) – provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms + - [**Token Bridge**](/docs/products/token-bridge/get-started/): Enables rapid and secure movement of DeFi assets. + - [**Connect**](/docs/products/connect/overview/): Provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms. ## Next Steps If you are looking for more guided practice, take a look at: -- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/) - perform token transfers using Wormhole’s Token Bridge, including manual and automatic transfers -- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/) - build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains -- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/) - craft a multichain token using Wormhole's Portal Bridge +- [**Get Started with Token Bridge**](/docs/products/token-bridge/get-started/): Perform token transfers using the Token Bridge, including manual and automatic transfers. +- [**Complete Token Transfer Flow**](/docs/products/token-bridge/tutorials/transfer-workflow/): Build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains. +- [**Create Multichain Tokens**](/docs/products/token-bridge/tutorials/multichain-token/): Craft a multichain token using Wormhole's Portal Bridge. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/tutorials/multichain-token/ @@ -19492,7 +19492,7 @@ A Spy can access the following categories of messages shared over the gossip pro For access to real-time network data without infrastructure overhead, follow this guide and use Wormhole Query to construct a query, make a request, and verify the response. - [:custom-arrow: Get Started with Queries](/docs/build/queries/use-queries/) + [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/) --- END CONTENT --- From 0647677360a4fd7b3cad76fa0c8dc93959553101 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 12:15:42 -0400 Subject: [PATCH 46/55] fix a few remaining 404s (#444) --- llms-files/llms-ntt.txt | 2 +- llms-files/llms-queries.txt | 8 +++----- llms-files/llms-transfer.txt | 2 +- llms-full.txt | 10 ++++------ .../native-token-transfers/guides/deploy-to-evm.md | 2 +- products/queries/get-started.md | 8 +++----- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 0effe95a6..de7658992 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -709,7 +709,7 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** +Wormhole’s NTT framework supports two [deployment models](/docs/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** ??? interface "Burn-and-Mint" diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 1f1c138e3..9d970a9a0 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -225,11 +225,9 @@ The expected output should be similar to this: Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: - - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM - - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually - - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts - -Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. +- [**Query Solana**](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank}: Try fetching Solana stake pools to see how cross-chain queries apply beyond EVM. +- [**Use Queries**](/docs/products/queries/guides/use-queries){target=\_blank}: Take a deeper look at the complete Queries lifecycle. +- **Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank}**: See where Queries are supported. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/guides/use-queries/ diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index dcfb63003..dcfb92ddb 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -5418,7 +5418,7 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** +Wormhole’s NTT framework supports two [deployment models](/docs/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** ??? interface "Burn-and-Mint" diff --git a/llms-full.txt b/llms-full.txt index bd6206636..900890fee 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -12355,7 +12355,7 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** +Wormhole’s NTT framework supports two [deployment models](/docs/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** ??? interface "Burn-and-Mint" @@ -13905,11 +13905,9 @@ The expected output should be similar to this: Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: - - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM - - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually - - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts - -Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. +- [**Query Solana**](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank}: Try fetching Solana stake pools to see how cross-chain queries apply beyond EVM. +- [**Use Queries**](/docs/products/queries/guides/use-queries){target=\_blank}: Take a deeper look at the complete Queries lifecycle. +- **Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank}**: See where Queries are supported. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/queries/guides/use-queries/ diff --git a/products/native-token-transfers/guides/deploy-to-evm.md b/products/native-token-transfers/guides/deploy-to-evm.md index 58b9e9250..1c9f351c0 100644 --- a/products/native-token-transfers/guides/deploy-to-evm.md +++ b/products/native-token-transfers/guides/deploy-to-evm.md @@ -16,7 +16,7 @@ If you still need to do so, deploy the token contract to the destination or spok ### Requirements for Token Deployment -Wormhole’s NTT framework supports two [deployment models](/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** +Wormhole’s NTT framework supports two [deployment models](/docs/products/native-token-transfers/overview#deployment-models){target=\_blank}: burn-and-mint and hub-and-spoke. **Both require an ERC-20 token (new or existing).** ??? interface "Burn-and-Mint" diff --git a/products/queries/get-started.md b/products/queries/get-started.md index 6407b0dc8..2b3978811 100644 --- a/products/queries/get-started.md +++ b/products/queries/get-started.md @@ -74,9 +74,7 @@ The expected output should be similar to this: Now that you've successfully run your first verifiable query, you are ready to go deeper. Check out the following guides to build on what you've learned: - - [Query Solana](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank} – try fetching Solana stake pools to see how cross-chain queries apply beyond EVM - - [Construct a Query](/docs/products/queries/guides/construct-a-query){target=\_blank} – understand how to build different query types using the SDK manually - - [Verify a Query Response On-Chain](/docs/products/queries/guides/verify-response){target=\_blank} – use signed results in smart contracts - -Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank} to see where you can query today. +- [**Query Solana**](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\_blank}: Try fetching Solana stake pools to see how cross-chain queries apply beyond EVM. +- [**Use Queries**](/docs/products/queries/guides/use-queries){target=\_blank}: Take a deeper look at the complete Queries lifecycle. +- **Browse the [Supported Networks](/docs/products/queries/reference/supported-networks){target=\_blank}**: See where Queries are supported. From bab713fcf6e56e5a18db731c05d5e67589564fb1 Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 30 May 2025 13:02:47 -0400 Subject: [PATCH 47/55] update table --- llms-files/llms-connect.txt | 16 ++-------------- llms-files/llms-multigov.txt | 16 ++-------------- llms-files/llms-ntt.txt | 16 ++-------------- llms-files/llms-queries.txt | 16 ++-------------- llms-files/llms-reference.txt | 16 ++-------------- llms-files/llms-relayers.txt | 16 ++-------------- llms-files/llms-settlement.txt | 16 ++-------------- llms-files/llms-solidity-sdk.txt | 16 ++-------------- llms-files/llms-token-bridge.txt | 16 ++-------------- llms-files/llms-transfer.txt | 16 ++-------------- llms-files/llms-typescript-sdk.txt | 16 ++-------------- llms-full.txt | 16 ++-------------- products/reference/contract-addresses.md | 16 ++-------------- 13 files changed, 26 insertions(+), 182 deletions(-) diff --git a/llms-files/llms-connect.txt b/llms-files/llms-connect.txt index 694414ad7..2126b3cf3 100644 --- a/llms-files/llms-connect.txt +++ b/llms-files/llms-connect.txt @@ -4731,23 +4731,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index adae33b10..3a5a39a2c 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -3977,23 +3977,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index de7658992..3c2201ec3 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -4933,23 +4933,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index 9d970a9a0..a5a7190b2 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -3743,23 +3743,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 88bb8d780..484298771 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -504,23 +504,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index af7648804..df28c1ef9 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -3496,23 +3496,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 310adf48d..04db1e53f 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -3816,23 +3816,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index e8f65f654..69a76639d 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -4549,23 +4549,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index 1408abfdc..0626669d3 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -4087,23 +4087,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index dcfb92ddb..a88de1a98 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -11105,23 +11105,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 9e3e3a9aa..43b401849 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -6790,23 +6790,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/llms-full.txt b/llms-full.txt index 900890fee..267c77156 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -14967,23 +14967,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments diff --git a/products/reference/contract-addresses.md b/products/reference/contract-addresses.md index cd47df0f7..cdf37eed7 100644 --- a/products/reference/contract-addresses.md +++ b/products/reference/contract-addresses.md @@ -26,23 +26,11 @@ categories: Reference === "Mainnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Ethereum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Solana | `28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe` | - | Arbitrum | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Avalanche | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Base | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Optimism | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | - | Polygon | `0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47` | +
    Chain NameContract Address
    Ethereum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Solana28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe
    Arbitrum0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Avalanche0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Base0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Optimism0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    Polygon0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47
    === "Testnet" - | Chain Name | Contract Address | - |----------------------|-------------------------------------------------| - | Solana | `tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md` | - | Arbitrum Sepolia | `0xe0418C44F06B0b0D7D1706E01706316DBB0B210E` | - | Optimism Sepolia | `0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8` | +
    Chain NameContract Address
    SolanatD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md
    Arbitrum Sepolia0xe0418C44F06B0b0D7D1706E01706316DBB0B210E
    Optimism Sepolia0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8
    ## Read-Only Deployments From 3caf3d174d1f113b0c92b78be0f295fef0130a22 Mon Sep 17 00:00:00 2001 From: Ilaria <43253244+ilariae@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:12:03 +0200 Subject: [PATCH 48/55] various fixes (#447) * adds supported networks to intro and glossary to ref * change demo link and fix lists * remove one integration three ways * coingecko api-key section of Connect removed * remoce spydk note * removes settlement guides * adjust overview page * intro settlement * nnt cli video * vaalib link * Apply suggestions from code review Co-authored-by: Erin Shaben * replace table with link --------- Co-authored-by: Ilaria Enache Co-authored-by: Erin Shaben Co-authored-by: Ilaria Enache --- products/connect/configuration/data.md | 10 +- .../native-token-transfers/get-started.md | 2 + products/reference/.pages | 1 + products/settlement/.pages | 1 - products/settlement/get-started.md | 1 - products/settlement/guides/.pages | 4 - products/settlement/guides/liquidity-layer.md | 97 ----------- products/settlement/guides/solver.md | 154 ----------------- products/settlement/overview.md | 39 ++--- .../tutorials/.settlement-routes.md | 156 ------------------ protocol/infrastructure-guides/run-spy.md | 3 - protocol/introduction.md | 36 ++-- tools/typescript-sdk/guides/vaas-protocols.md | 2 +- 13 files changed, 32 insertions(+), 474 deletions(-) delete mode 100644 products/settlement/guides/.pages delete mode 100644 products/settlement/guides/liquidity-layer.md delete mode 100644 products/settlement/guides/solver.md delete mode 100644 products/settlement/tutorials/.settlement-routes.md diff --git a/products/connect/configuration/data.md b/products/connect/configuration/data.md index b7c95d59d..736c5ead9 100644 --- a/products/connect/configuration/data.md +++ b/products/connect/configuration/data.md @@ -157,12 +157,4 @@ Your selected blockchain network determines the available wallet options when us The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. -If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. - -### CoinGecko API Key {: #coingecko-api-key } - -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. - -```jsx ---8<-- 'code/products/connect/configuration/data/custom-coingecko-key.jsx' -``` +If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. \ No newline at end of file diff --git a/products/native-token-transfers/get-started.md b/products/native-token-transfers/get-started.md index a9486e77a..3adfed3ce 100644 --- a/products/native-token-transfers/get-started.md +++ b/products/native-token-transfers/get-started.md @@ -130,6 +130,8 @@ To use NTT, you must have a token already deployed on the source and destination ## Install NTT CLI +
    + The NTT CLI is recommended to deploy and manage your cross-chain token configuration. 1. Run the installation command in your terminal: diff --git a/products/reference/.pages b/products/reference/.pages index a17e39d11..26b760b36 100644 --- a/products/reference/.pages +++ b/products/reference/.pages @@ -6,3 +6,4 @@ nav: - 'Wormhole-Formatted Addresses': wormhole-formatted-addresses.md - 'Supported Networks': supported-networks.md - 'Testnet Faucets': testnet-faucets.md +- 'Glossary': glossary.md diff --git a/products/settlement/.pages b/products/settlement/.pages index b5c7e2d07..b814f1820 100644 --- a/products/settlement/.pages +++ b/products/settlement/.pages @@ -2,6 +2,5 @@ title: Settlement nav: - 'Overview': overview.md - 'Get Started': get-started.md -- guides - concepts - 'FAQs': faqs.md diff --git a/products/settlement/get-started.md b/products/settlement/get-started.md index 19312fa15..e998c8df7 100644 --- a/products/settlement/get-started.md +++ b/products/settlement/get-started.md @@ -107,5 +107,4 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: - [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. -- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. diff --git a/products/settlement/guides/.pages b/products/settlement/guides/.pages deleted file mode 100644 index 8569cf10a..000000000 --- a/products/settlement/guides/.pages +++ /dev/null @@ -1,4 +0,0 @@ -title: Guides -nav: -- 'Build on the Liquidity Layer': 'liquidity-layer.md' -- 'Run a Solver': 'solver.md' diff --git a/products/settlement/guides/liquidity-layer.md b/products/settlement/guides/liquidity-layer.md deleted file mode 100644 index 28e16a0af..000000000 --- a/products/settlement/guides/liquidity-layer.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- - -# Build on the Wormhole Liquidity Layer - -## Introduction - -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. - -## EVM Functions - -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - -See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. - -### Fast Market Order - -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` - -```solidity title="`placeFastMarketOrder` Interface" ---8<-- 'code/products/settlement/guides/liquidity-layer/placeFastMarketOrder.sol' -``` - -??? interface "Parameters `placeFastMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - - --- - - `maxFee` ++"uint128"++ - - The maximum fee the user wants to pay to execute a fast transfer. - - --- - - `deadline` ++"uint32"++ - - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. - -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. - -### Market Order - -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. - -```solidity title="`placeMarketOrder` Interface" ---8<-- 'code/products/settlement/guides/liquidity-layer/placeMarketOrder.sol' -``` - -??? interface "Parameters `placeMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. diff --git a/products/settlement/guides/solver.md b/products/settlement/guides/solver.md deleted file mode 100644 index 93adfc77a..000000000 --- a/products/settlement/guides/solver.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- - -# Run a Wormhole Settlement Solver - -## Introduction - -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. - -A Solver is an off-chain agent responsible for: - -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana - -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. - -## Background - -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: - -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners - -These instructions work together to carry out the auction as follows: - -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. - -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. - -## Testnet Example Solver - -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. - -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. - -### Prerequisites - -In order to build and install dependencies locally in this repo, you will need: - -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} - -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: - -```sh -make dependencies -``` - -### Set up Config - -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. - -```json title="config.json" ---8<-- 'code/products/settlement/guides/solver/solver-config.json' -``` - -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. - -### Listen to Activity - -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. - -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` - -You should see output resembling: - -
    - Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
    - -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: - -=== "Linux" - - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` - -=== "MacOS" - - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` - -### Running the Example Solver - -Using the same config for your publisher, run the example solver with the command below. - -```sh -CONFIG=path/to/config.json make run-solver -``` - -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. - -This process reads the following environment variables: - -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` - -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. - -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. - -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. - -An address lookup table is required to execute some transactions. Use the command below to create one. - -```sh -CONFIG=path/to/config.json make create-lut -``` - -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. - -The example solver has the following toggles depending on which orders you want to fulfill: - -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` - -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. - -This example solver does NOT do the following: - -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want - - diff --git a/products/settlement/overview.md b/products/settlement/overview.md index c5ec53511..30895e233 100644 --- a/products/settlement/overview.md +++ b/products/settlement/overview.md @@ -6,19 +6,20 @@ categories: Settlement, Transfer # Settlement Overview -Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. +Wormhole Settlement is a multichain transfer system that allows users to specify what they want to happen, such as sending or swapping tokens, without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. -Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. +Settlement prioritizes speed, execution quality, and reliability. Its primary route, Mayan Swift, leverages fast off-chain auctions among a curated set of solvers to achieve low-latency bridging with minimal slippage. All settlement steps remain verifiable on-chain through Wormhole messages. -It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. +For broader use cases and protocol-level execution, Mayan MCTP provides an alternative path. It wraps Circle’s CCTP to facilitate native USDC bridging and token delivery in a single, verifiable flow. While slower due to chain finality constraints, MCTP offers a reliable mechanism for cross-chain transfers. ## Key Features - **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. - **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. -- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Fast and fallback-capable**: Combines high-speed execution with a reliable fallback path. - **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. -- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. +- **On-chain verifiability**: Even though auctions are off-chain, all settlement steps remain verifiable on-chain via Wormhole messages. +- **Two integrated routes**: Mayan Swift for speed, Mayan MCTP for compatibility and redundancy. ## How It Works @@ -27,7 +28,7 @@ At the core of Settlement are two components: - **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. - **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. -Settlement leverages the following three integrated protocols. +Settlement currently supports the following integrated protocols. ### Mayan Swift @@ -37,7 +38,7 @@ The diagram below shows how Mayan Swift handles a cross-chain intent when a user 1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. 2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. -3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +3. **User receives WIF**: Once the user receives WIF, a second VAA is emitted to finalize the transfer and releases the ETH held in the escrow to the solver. 4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. ```mermaid @@ -63,27 +64,9 @@ sequenceDiagram Escrow->>Solver_ARB: Releases ETH to solver ``` -### Liquidity Layer - -The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. - ### Mayan MCTP -Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. - -### One Integration, Three Ways - -Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. - -By default, Settlement integrates all three: - -- The SDK automatically resolves the best route for each transfer. -- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. -- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. - -Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. - -To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift. While typically more expensive due to protocol fees, it ensures reliable settlement when faster options are unavailable. ## Use Cases @@ -107,6 +90,4 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: - **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. -- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. -- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. - +- **[Architecture Documentation](/docs/products/settlement/concepts/architecture/)**: Explore the Settlement architecture and components. \ No newline at end of file diff --git a/products/settlement/tutorials/.settlement-routes.md b/products/settlement/tutorials/.settlement-routes.md deleted file mode 100644 index e1d6ec2b4..000000000 --- a/products/settlement/tutorials/.settlement-routes.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Wormhole Settlements -description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. ---- - -# Integrate Wormhole Settlement Routes Using the SDK - -## Introduction - -This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. - -## Prerequisites - -Before beginning this project, make sure you have the following: - -- **Wormhole SDK Route package** - installed using your preferred package manager - - To install the package with npm, run the following command in your terminal: - - ```sh - npm install @mayan-finance/wormhole-sdk-route - ``` - - Alternatively, clone the repository and install dependencies: - - ```sh - git clone https://github.com/mayan-finance/wormhole-sdk-route.git - cd wormhole-sdk-route - npm install - ``` - -- **Data for parameters** - you will need: - - - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - - An contract address for the token you want to swap and the token you want to receive on the destination chain - -## Configure and Setup - -To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: - -- `sourceChain` - identifier for the chain where the swap begins -- `destinationChain` - identifier for the target chain -- `inputTokenAddress` - address of the token you want to swap -- `outputTokenAddress` - identifier/address of the desired token on the destination chain -- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) -- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) - -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - -const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana - amount: '1000000000000000000', // For instance, 1 token in wei - slippageTolerance: 0.005, // 0.5% slippage tolerance - // Additional parameters may be included as needed -}; - -const swapRoute = new SwapRoute(config); -``` - -## Execute a Swap - -Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. - -### Fetch the Swap Route - -Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: - -```ts -async function getSwapDetails() { - try { - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - return routeDetails; - } catch (error) { - console.error('Error fetching swap route:', error); - throw error; - } -} - -getSwapDetails(); -``` - -### Execute the Swap Transaction - -Once the route is confirmed, execute the swap: - -```ts -async function executeSwap() { - try { - const txResponse = await swapRoute.executeSwap(); - console.log('Swap executed successfully:', txResponse); - // Further transaction handling (e.g., waiting for confirmation) can be added here. - } catch (error) { - console.error('Swap execution failed:', error); - } -} - -executeSwap(); -``` - -## Complete Example Integration - -Below is a complete example that puts together configuration, route fetching, and swap execution: - -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - -async function performSwap() { - // Configure the swap parameters - const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', - amount: '1000000000000000000', - slippageTolerance: 0.005, - // Include additional settings as needed - }; - - // Initialize the swap route - const swapRoute = new SwapRoute(config); - - try { - // Retrieve the optimal swap route details - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - - // Execute the swap transaction - const txResponse = await swapRoute.executeSwap(); - console.log('Swap Transaction Response:', txResponse); - } catch (error) { - console.error('An error occurred during the swap process:', error); - } -} - -performSwap(); -``` - -## Error Handling and Troubleshooting - -- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable -- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting -- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: - - ```ts - class MayanRefRoute extends MayanRoute { - override referrerAddress(): ReferrerAddresses | undefined { - return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; - } - } - ``` - diff --git a/protocol/infrastructure-guides/run-spy.md b/protocol/infrastructure-guides/run-spy.md index 3ddc75068..3a8655d53 100644 --- a/protocol/infrastructure-guides/run-spy.md +++ b/protocol/infrastructure-guides/run-spy.md @@ -70,9 +70,6 @@ Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your prog Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. -!!! note - If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. - ## Data Persistence The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. diff --git a/protocol/introduction.md b/protocol/introduction.md index 2a77a985b..eb7385d05 100644 --- a/protocol/introduction.md +++ b/protocol/introduction.md @@ -27,44 +27,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. + +
    + +### CCTP + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/build/start-building/supported-networks/connect.md b/.snippets/text/build/start-building/supported-networks/connect.md new file mode 100644 index 000000000..bb2f6ba13 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/connect.md @@ -0,0 +1,10 @@ + + +
    + +### Connect + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SolanaSVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AptosMove VM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BerachainEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BNB Smart ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MezoEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OsmosisCosmWasm:x::x::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SuiSui Move VM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/build/start-building/supported-networks/multigov.md b/.snippets/text/build/start-building/supported-networks/multigov.md new file mode 100644 index 000000000..a1207f33a --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/multigov.md @@ -0,0 +1,10 @@ + + +
    + +### MultiGov + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BerachainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BlastEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    CeloEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    FantomEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    GnosisEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    HyperEVMEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    InkEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    KaiaEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    LineaEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MantleEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MezoEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MonadEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MoonbeamEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    NeonEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ScrollEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SeiCosmWasm:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SeievmEVM:white_check_mark::white_check_mark::white_check_mark:
    SNAXchainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SonicEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    UnichainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    World ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    X LayerEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/build/start-building/supported-networks/ntt.md b/.snippets/text/build/start-building/supported-networks/ntt.md new file mode 100644 index 000000000..1df252e00 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/ntt.md @@ -0,0 +1,10 @@ + + +
    + +### NTT + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BerachainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    GnosisEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    HyperEVMEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    InkEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    KaiaEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    LineaEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MezoEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MonadEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    NeonEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SeievmEVM:white_check_mark::white_check_mark::x:
    SNAXchainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/build/start-building/supported-networks/settlement.md b/.snippets/text/build/start-building/supported-networks/settlement.md new file mode 100644 index 000000000..532bd9d38 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/settlement.md @@ -0,0 +1,10 @@ + + +
    + +### Settlement + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SolanaSVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SuiSui Move VM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    UnichainEVM:white_check_mark::x::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/build/start-building/supported-networks/token-bridge.md b/.snippets/text/build/start-building/supported-networks/token-bridge.md new file mode 100644 index 000000000..96a09e420 --- /dev/null +++ b/.snippets/text/build/start-building/supported-networks/token-bridge.md @@ -0,0 +1,10 @@ + + +
    + +### Token Bridge + +
    BlockchainEnvironmentMainnetTestnetDevnetQuick Links
    EthereumEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SolanaSVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AlgorandAVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AptosMove VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ArbitrumEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    AvalancheEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BaseEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BerachainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BlastEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    BNB Smart ChainEVM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    CeloEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    FantomEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    HyperEVMEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    InjectiveCosmWasm:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    InkEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    KaiaEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    LineaEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MantleEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MezoEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MonadEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    MoonbeamEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    NEARNEAR VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    NeonEVM:x::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    OptimismEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    PolygonEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    ScrollEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SeiCosmWasm:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SeievmEVM:white_check_mark::white_check_mark::x:
    SNAXchainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    SuiSui Move VM:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    Terra 2.0CosmWasm:white_check_mark::white_check_mark::white_check_mark::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    UnichainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    World ChainEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    X LayerEVM:white_check_mark::white_check_mark::x::material-web: Website
    :material-file-document: Developer Docs
    :octicons-package-16: Block Explorer
    + +
    + diff --git a/.snippets/text/products/reference/chain-ids/chain-ids.md b/.snippets/text/products/reference/chain-ids/chain-ids.md index 4d438ef80..700a06941 100644 --- a/.snippets/text/products/reference/chain-ids/chain-ids.md +++ b/.snippets/text/products/reference/chain-ids/chain-ids.md @@ -3,10 +3,10 @@ === "Mainnet" -
    Chain NameWormhole Chain IDNetwork ID
    Ethereum21
    Solana1Mainnet Beta - 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
    Acala12787
    Algorand8mainnet-v1.0
    Aptos221
    Arbitrum23Arbitrum One - 42161
    Avalanche6C-Chain - 43114
    Base30Base - 8453
    Berachain39
    Blast3681457
    BNB Smart Chain456
    Celestia4004celestia
    Celo1442220
    Cosmos Hub4000cosmoshub-4
    Dymension4007dymension_1100-1
    Evmos4001evmos_9001-2
    Fantom10250
    Gnosis25100
    HyperEVM47
    Injective19injective-1
    Ink46
    Kaia138217
    Karura11686
    Kujira4002kaiyo-1
    Linea3859144
    Mantle355000
    Mezo50
    Monad48
    Moonbeam161284
    NEAR15mainnet
    Neon17245022934
    Neutron4003neutron-1
    Noble4009noble-1
    Oasis742262
    Optimism2410
    Osmosis20osmosis-1
    Polygon5137
    Provenance4008pio-mainnet-1
    Pythnet26
    Scroll34534352
    SEDA4006
    Sei32pacific-1
    Seievm40
    SNAXchain432192
    Sonic52146
    Stargaze4005stargaze-1
    Sui2135834a8a
    Terra3columbus-5
    Terra 2.018phoenix-1
    Unichain44
    World Chain45480
    X Layer37196
    XPLA28dimension_37-1
    +
    Chain NameWormhole Chain IDNetwork ID
    Ethereum21
    Solana1Mainnet Beta - 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
    Algorand8mainnet-v1.0
    Aptos221
    Arbitrum23Arbitrum One - 42161
    Avalanche6C-Chain - 43114
    Base30Base - 8453
    Berachain39
    Blast3681457
    BNB Smart Chain456
    Celestia4004celestia
    Celo1442220
    Cosmos Hub4000cosmoshub-4
    Dymension4007dymension_1100-1
    Evmos4001evmos_9001-2
    Fantom10250
    Gnosis25100
    HyperEVM47
    Injective19injective-1
    Ink46
    Kaia138217
    Kujira4002kaiyo-1
    Linea3859144
    Mantle355000
    Mezo50
    Monad48
    Moonbeam161284
    NEAR15mainnet
    Neon17245022934
    Neutron4003neutron-1
    Noble4009noble-1
    Optimism2410
    Osmosis20osmosis-1
    Polygon5137
    Provenance4008pio-mainnet-1
    Pythnet26
    Scroll34534352
    SEDA4006
    Sei32pacific-1
    Seievm40
    SNAXchain432192
    Sonic52146
    Stargaze4005stargaze-1
    Sui2135834a8a
    Terra 2.018phoenix-1
    Unichain44
    World Chain45480
    X Layer37196
    === "Testnet" -
    Chain NameWormhole Chain IDNetwork ID
    Ethereum Holesky10006Holesky - 17000
    Ethereum Sepolia10002Sepolia - 11155111
    Solana1Devnet - EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
    Acala12597
    Algorand8testnet-v1.0
    Aptos222
    Arbitrum Sepolia10003Sepolia - 421614
    Avalanche6Fuji - 43113
    Base Sepolia10004Base Sepolia - 84532
    Berachain3980084
    Blast36168587773
    BNB Smart Chain497
    Celestia4004mocha-4
    Celo14Alfajores - 44787
    Cosmos Hub4000theta-testnet-001
    Dymension4007
    Evmos4001evmos_9000-4
    Fantom104002
    Gnosis25Chiado - 10200
    HyperEVM47998
    Injective19injective-888
    Ink46763373
    Kaia13Kairos - 1001
    Karura11596
    Kujira4002harpoon-4
    Linea3859141
    Mantle35Sepolia - 5003
    Mezo5031611
    Monad4810143
    Moonbeam16Moonbase-Alphanet - 1287
    NEAR15testnet
    Neon17245022940
    Neutron4003pion-1
    Noble4009grand-1
    Oasis742261
    Optimism Sepolia10005Optimism Sepolia - 11155420
    Osmosis20osmo-test-5
    Polygon Amoy10007Amoy - 80002
    Provenance4008
    Pythnet26
    Scroll34Sepolia - 534351
    SEDA4006seda-1-testnet
    Sei32atlantic-2
    Seievm40
    SNAXchain4313001
    Sonic5257054
    Stargaze4005
    Sui214c78adac
    Terra3bombay-12
    Terra 2.018pisco-1
    Unichain44Unichain Sepolia - 1301
    World Chain454801
    X Layer37195
    XPLA28cube_47-5
    +
    Chain NameWormhole Chain IDNetwork ID
    Ethereum Holesky10006Holesky - 17000
    Ethereum Sepolia10002Sepolia - 11155111
    Solana1Devnet - EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
    Algorand8testnet-v1.0
    Aptos222
    Arbitrum Sepolia10003Sepolia - 421614
    Avalanche6Fuji - 43113
    Base Sepolia10004Base Sepolia - 84532
    Berachain3980084
    Blast36168587773
    BNB Smart Chain497
    Celestia4004mocha-4
    Celo14Alfajores - 44787
    Cosmos Hub4000theta-testnet-001
    Dymension4007
    Evmos4001evmos_9000-4
    Fantom104002
    Gnosis25Chiado - 10200
    HyperEVM47998
    Injective19injective-888
    Ink46763373
    Kaia13Kairos - 1001
    Kujira4002harpoon-4
    Linea3859141
    Mantle35Sepolia - 5003
    Mezo5031611
    Monad4810143
    Moonbeam16Moonbase-Alphanet - 1287
    NEAR15testnet
    Neon17245022940
    Neutron4003pion-1
    Noble4009grand-1
    Optimism Sepolia10005Optimism Sepolia - 11155420
    Osmosis20osmo-test-5
    Polygon Amoy10007Amoy - 80002
    Provenance4008
    Pythnet26
    Scroll34Sepolia - 534351
    SEDA4006seda-1-testnet
    Sei32atlantic-2
    Seievm40
    SNAXchain4313001
    Sonic5257054
    Stargaze4005
    Sui214c78adac
    Terra 2.018pisco-1
    Unichain44Unichain Sepolia - 1301
    World Chain454801
    X Layer37195
    \ No newline at end of file diff --git a/.snippets/text/products/reference/consistency-levels/consistency-levels.md b/.snippets/text/products/reference/consistency-levels/consistency-levels.md index cc7221a5b..061dd6c35 100644 --- a/.snippets/text/products/reference/consistency-levels/consistency-levels.md +++ b/.snippets/text/products/reference/consistency-levels/consistency-levels.md @@ -1,4 +1,4 @@ -
    ChainInstantSafeFinalizedOtherwiseTime to FinalizeDetails
    Ethereum200201finalized~ 19minDetails
    Solana01~ 14sDetails
    Acala200201finalized~ 24s
    Algorand0~ 4sDetails
    Aptos0~ 4sDetails
    Arbitrum200201finalized~ 18minDetails
    Avalanche200finalized~ 2sDetails
    Base200201finalized~ 18min
    Berachain200finalized~ 4s
    Blast200201finalized~ 18min
    BNB Smart Chain200201finalized~ 48sDetails
    Celestia0~ 5s
    Celo200finalized~ 10s
    Cosmos Hub0~ 5s
    Dymension0~ 5s
    Evmos0~ 2s
    Fantom200finalized~ 5s
    Injective0~ 3s
    Ink0~ 9min
    Kaia200finalized~ 1s
    Karura200201finalized~ 24sDetails
    Kujira0~ 3s
    Mantle200201finalized~ 18min
    Mezo0~ 8s
    Monad0~ 2s
    Moonbeam200201finalized~ 24sDetails
    NEAR0~ 2sDetails
    Neutron0~ 5s
    Oasis200finalized~ 12s
    Optimism200201finalized~ 18min
    Osmosis0~ 6s
    Polygon200finalized~ 66sDetails
    Scroll200finalized~ 16min
    Sei0~ 1s
    Sonic0~ 1s
    Stargaze0~ 5s
    Sui0~ 3sDetails
    Terra0~ 6s
    Terra 2.00~ 6s
    Unichain200201finalized~ 18min
    World Chain0~ 18min
    X Layer200201finalized~ 16min
    XPLA0~ 5s
    +
    ChainInstantSafeFinalizedOtherwiseTime to FinalizeDetails
    Ethereum200201finalized~ 19minDetails
    Solana01~ 14sDetails
    Algorand0~ 4sDetails
    Aptos0~ 4sDetails
    Arbitrum200201finalized~ 18minDetails
    Avalanche200finalized~ 2sDetails
    Base200201finalized~ 18min
    Berachain200finalized~ 4s
    Blast200201finalized~ 18min
    BNB Smart Chain200201finalized~ 48sDetails
    Celestia0~ 5s
    Celo200finalized~ 10s
    Cosmos Hub0~ 5s
    Dymension0~ 5s
    Evmos0~ 2s
    Fantom200finalized~ 5s
    Injective0~ 3s
    Ink0~ 9min
    Kaia200finalized~ 1s
    Kujira0~ 3s
    Mantle200201finalized~ 18min
    Mezo0~ 8s
    Monad0~ 2s
    Moonbeam200201finalized~ 24sDetails
    NEAR0~ 2sDetails
    Neutron0~ 5s
    Optimism200201finalized~ 18min
    Osmosis0~ 6s
    Polygon200finalized~ 66sDetails
    Scroll200finalized~ 16min
    Sei0~ 1s
    Sonic0~ 1s
    Stargaze0~ 5s
    Sui0~ 3sDetails
    Terra 2.00~ 6s
    Unichain200201finalized~ 18min
    World Chain0~ 18min
    X Layer200201finalized~ 16min
    diff --git a/.snippets/text/products/reference/contract-addresses/core-contracts.md b/.snippets/text/products/reference/contract-addresses/core-contracts.md index 1a294ccf7..927cd2194 100644 --- a/.snippets/text/products/reference/contract-addresses/core-contracts.md +++ b/.snippets/text/products/reference/contract-addresses/core-contracts.md @@ -3,14 +3,14 @@ === "Mainnet" -
    Chain NameContract Address
    Ethereum0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
    Solanaworm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
    Acala0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Algorand842125965
    Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
    Arbitrum0xa5f208e072434bC67592E4C49C1B991BA79BCA46
    Avalanche0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c
    Base0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Berachain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    Blast0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    BNB Smart Chain0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
    Celo0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Fantom0x126783A6Cb203a3E35344528B26ca3a0489a1485
    Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Injectiveinj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d
    Ink0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    Kaia0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7
    Karura0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Mantle0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Moonbeam0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3
    NEARcontract.wormhole_crypto.near
    Neutronneutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh
    Oasis0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585
    Optimism0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722
    Polygon0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7
    PythnetH3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU
    Scroll0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Seisei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn
    Seievm0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    SNAXchain0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4
    Sui0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c
    Terraterra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5
    Terra 2.0terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp
    Unichain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    World Chain0xcbcEe4e081464A15d8Ad5f58BB493954421eB506
    X Layer0x194B123c5E96B9b2E49763619985790Dc241CAC0
    XPLAxpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w
    +
    Chain NameContract Address
    Ethereum0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
    Solanaworm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth
    Algorand842125965
    Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
    Arbitrum0xa5f208e072434bC67592E4C49C1B991BA79BCA46
    Avalanche0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c
    Base0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Berachain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    Blast0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    BNB Smart Chain0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
    Celo0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Fantom0x126783A6Cb203a3E35344528B26ca3a0489a1485
    Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    HyperEVM0x7C0faFc4384551f063e05aee704ab943b8B53aB3
    Injectiveinj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d
    Ink0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    Kaia0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7
    Mantle0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Moonbeam0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3
    NEARcontract.wormhole_crypto.near
    Neutronneutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh
    Optimism0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722
    Polygon0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7
    PythnetH3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU
    Scroll0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Seisei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn
    Seievm0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    SNAXchain0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4
    Sui0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c
    Terra 2.0terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp
    Unichain0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D
    World Chain0xcbcEe4e081464A15d8Ad5f58BB493954421eB506
    X Layer0x194B123c5E96B9b2E49763619985790Dc241CAC0
    === "Testnet" -
    Chain NameContract Address
    Ethereum Holesky0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Ethereum Sepolia0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
    Solana3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5
    Acala0x64fb09E405D2043ed7785a29E296C766D56F2056
    Algorand86525623
    Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
    Arbitrum Sepolia0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35
    Avalanche0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C
    Base Sepolia0x79A1027a6A159502049F10906D333EC57E95F083
    Berachain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Blast0x473e002D7add6fB67a4964F13bFd61280Ca46886
    BNB Smart Chain0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D
    Celo0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56
    Fantom0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7
    Gnosis0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    HyperEVM0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Injectiveinj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg
    Ink0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Kaia0x1830CC6eE66c84D2F177B94D544967c774E624cA
    Karura0x64fb09E405D2043ed7785a29E296C766D56F2056
    Linea0x79A1027a6A159502049F10906D333EC57E95F083
    Mantle0x376428e7f26D5867e69201b275553C45B09EE090
    Mezo0x268557122Ffd64c85750d630b716471118F323c8
    Monad0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Moonbeam0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901
    NEARwormhole.wormhole.testnet
    Neon0x268557122Ffd64c85750d630b716471118F323c8
    Neutronneutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4
    Oasis0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb
    Optimism Sepolia0x31377888146f3253211EFEf5c676D41ECe7D58Fe
    Osmosisosmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx
    Polygon Amoy0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35
    PythnetEUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z
    Scroll0x055F47F1250012C6B20c436570a76e52c17Af2D5
    Seisei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s
    Seievm0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    SNAXchain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Sui0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790
    Terraterra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v
    Terra 2.0terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0
    Unichain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    World Chain0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A
    X Layer0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780
    XPLAxpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35
    +
    Chain NameContract Address
    Ethereum Holesky0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Ethereum Sepolia0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
    Solana3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5
    Algorand86525623
    Aptos0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625
    Arbitrum Sepolia0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35
    Avalanche0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C
    Base Sepolia0x79A1027a6A159502049F10906D333EC57E95F083
    Berachain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Blast0x473e002D7add6fB67a4964F13bFd61280Ca46886
    BNB Smart Chain0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D
    Celo0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56
    Fantom0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7
    Gnosis0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    HyperEVM0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Injectiveinj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg
    Ink0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Kaia0x1830CC6eE66c84D2F177B94D544967c774E624cA
    Linea0x79A1027a6A159502049F10906D333EC57E95F083
    Mantle0x376428e7f26D5867e69201b275553C45B09EE090
    Mezo0x268557122Ffd64c85750d630b716471118F323c8
    Monad0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Moonbeam0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901
    NEARwormhole.wormhole.testnet
    Neon0x268557122Ffd64c85750d630b716471118F323c8
    Neutronneutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4
    Optimism Sepolia0x31377888146f3253211EFEf5c676D41ECe7D58Fe
    Osmosisosmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx
    Polygon Amoy0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35
    PythnetEUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z
    Scroll0x055F47F1250012C6B20c436570a76e52c17Af2D5
    Seisei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s
    Seievm0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    SNAXchain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    Sui0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790
    Terra 2.0terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0
    Unichain0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd
    World Chain0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A
    X Layer0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780
    === "Devnet" -
    Chain NameContract Address
    Ethereum0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
    SolanaBridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o
    Algorand1004
    Aptos0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017
    BNB Smart Chain0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
    NEARwormhole.test.near
    Sui0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0
    Terraterra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au
    Terra 2.0terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au
    +
    Chain NameContract Address
    Ethereum0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
    SolanaBridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o
    Algorand1004
    Aptos0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017
    BNB Smart Chain0xC89Ce4735882C9F0f0FE26686c53074E09B0D550
    NEARwormhole.test.near
    Sui0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0
    Terra 2.0terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au
    diff --git a/.snippets/text/products/reference/contract-addresses/read-only.md b/.snippets/text/products/reference/contract-addresses/read-only.md index 2474edada..f507a9902 100644 --- a/.snippets/text/products/reference/contract-addresses/read-only.md +++ b/.snippets/text/products/reference/contract-addresses/read-only.md @@ -1,3 +1,17 @@ === "Mainnet" -
    Chain NameContract Address
    Corn0xa683c66045ad16abb1bCE5ad46A64d95f9A25785
    Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Goat0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    LightLink0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Rootstock0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Sonic0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Telos0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    \ No newline at end of file + + + + + + + + + + + + + + +
    Chain NameContract Address
    Acala0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Corn0xa683c66045ad16abb1bCE5ad46A64d95f9A25785
    Gnosis0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    Goat0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Karura0xa321448d90d4e5b0A732867c18eA198e75CAC48E
    LightLink0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Oasis0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585
    Rootstock0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
    Sonic0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Telos0x352A86168e6988A1aDF9A15Cb00017AAd3B67155
    Terraterra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5
    XPLAxpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w
    \ No newline at end of file diff --git a/.snippets/text/products/reference/contract-addresses/relayer.md b/.snippets/text/products/reference/contract-addresses/relayer.md index cc692eed9..e97d9db36 100644 --- a/.snippets/text/products/reference/contract-addresses/relayer.md +++ b/.snippets/text/products/reference/contract-addresses/relayer.md @@ -3,11 +3,11 @@ === "Mainnet" -
    Chain NameContract Address
    Ethereum0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Arbitrum0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Avalanche0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Base0x706f82e9bb5b0813501714ab5974216704980e31
    Berachain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Blast0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    BNB Smart Chain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Celo0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Fantom0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Ink0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Kaia0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Mantle0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Moonbeam0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Optimism0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Polygon0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Scroll0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    SNAXchain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Unichain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    World Chain0x1520cc9e779c56dab5866bebfb885c86840c33d3
    X Layer0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    +
    Chain NameContract Address
    Ethereum0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Arbitrum0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Avalanche0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Base0x706f82e9bb5b0813501714ab5974216704980e31
    Berachain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Blast0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    BNB Smart Chain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Celo0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Fantom0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Ink0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Kaia0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Mantle0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Moonbeam0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Optimism0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Polygon0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Scroll0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Seievm0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    SNAXchain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    Unichain0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    World Chain0x1520cc9e779c56dab5866bebfb885c86840c33d3
    X Layer0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
    === "Testnet" -
    Chain NameContract Address
    Ethereum Sepolia0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Arbitrum Sepolia0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Avalanche0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB
    Base Sepolia0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE
    Berachain0x362fca37E45fe1096b42021b543f462D49a5C8df
    BNB Smart Chain0x80aC94316391752A193C1c47E27D382b507c93F3
    Celo0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84
    Fantom0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Ink0x362fca37E45fe1096b42021b543f462D49a5C8df
    Monad0x362fca37E45fe1096b42021b543f462D49a5C8df
    Moonbeam0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0
    Optimism Sepolia0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE
    Seievm0x362fca37E45fe1096b42021b543f462D49a5C8df
    Unichain0x362fca37E45fe1096b42021b543f462D49a5C8df
    +
    Chain NameContract Address
    Ethereum Sepolia0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Arbitrum Sepolia0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Avalanche0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB
    Base Sepolia0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE
    Berachain0x362fca37E45fe1096b42021b543f462D49a5C8df
    BNB Smart Chain0x80aC94316391752A193C1c47E27D382b507c93F3
    Celo0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84
    Fantom0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470
    Ink0x362fca37E45fe1096b42021b543f462D49a5C8df
    Monad0x362fca37E45fe1096b42021b543f462D49a5C8df
    Moonbeam0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0
    Optimism Sepolia0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE
    Polygon Amoy0x362fca37E45fe1096b42021b543f462D49a5C8df
    Seievm0x362fca37E45fe1096b42021b543f462D49a5C8df
    Unichain0x362fca37E45fe1096b42021b543f462D49a5C8df
    === "Devnet" diff --git a/.snippets/text/products/reference/contract-addresses/token-bridge.md b/.snippets/text/products/reference/contract-addresses/token-bridge.md index f88b2a607..a82ab3360 100644 --- a/.snippets/text/products/reference/contract-addresses/token-bridge.md +++ b/.snippets/text/products/reference/contract-addresses/token-bridge.md @@ -3,14 +3,14 @@ === "Mainnet" -
    Chain NameContract Address
    Ethereum0x3ee18B2214AFF97000D974cf647E7C347E8fa585
    SolanawormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
    Acala0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
    Algorand842126029
    Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
    Arbitrum0x0b2402144Bb366A632D14B83F244D2e0e21bD39c
    Avalanche0x0e082F06FF657D94310cB8cE8B0D9a04541d8052
    Base0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627
    Berachain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    Blast0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    BNB Smart Chain0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7
    Celo0x796Dff6D74F3E27060B71255Fe517BFb23C93eed
    Fantom0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2
    Injectiveinj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn
    Ink0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    Kaia0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F
    Karura0xae9d7fe007b3327AA64A32824Aaac52C42a6E624
    Mantle0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    Moonbeam0xb1731c586ca89a23809861c6103f0b96b3f57d92
    NEARcontract.portalbridge.near
    Oasis0x5848C791e09901b40A9Ef749f2a6735b418d7564
    Optimism0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b
    Polygon0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE
    Scroll0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    Seisei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3
    Seievm0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    SNAXchain0x8B94bfE456B48a6025b92E11Be393BAa86e68410
    Sui0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9
    Terraterra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf
    Terra 2.0terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9
    Unichain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    World Chain0xc309275443519adca74c9136b02A38eF96E3a1f6
    X Layer0x5537857664B0f9eFe38C9f320F75fEf23234D904
    XPLAxpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv
    +
    Chain NameContract Address
    Ethereum0x3ee18B2214AFF97000D974cf647E7C347E8fa585
    SolanawormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb
    Algorand842126029
    Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
    Arbitrum0x0b2402144Bb366A632D14B83F244D2e0e21bD39c
    Avalanche0x0e082F06FF657D94310cB8cE8B0D9a04541d8052
    Base0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627
    Berachain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    Blast0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    BNB Smart Chain0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7
    Celo0x796Dff6D74F3E27060B71255Fe517BFb23C93eed
    Fantom0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2
    Injectiveinj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn
    Ink0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    Kaia0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F
    Mantle0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    Moonbeam0xb1731c586ca89a23809861c6103f0b96b3f57d92
    NEARcontract.portalbridge.near
    Optimism0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b
    Polygon0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE
    Scroll0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d
    Seisei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3
    Seievm0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    SNAXchain0x8B94bfE456B48a6025b92E11Be393BAa86e68410
    Sui0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9
    Terra 2.0terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9
    Unichain0x3Ff72741fd67D6AD0668d93B41a09248F4700560
    World Chain0xc309275443519adca74c9136b02A38eF96E3a1f6
    X Layer0x5537857664B0f9eFe38C9f320F75fEf23234D904
    === "Testnet" -
    Chain NameContract Address
    Ethereum Holesky0x76d093BbaE4529a342080546cAFEec4AcbA59EC6
    Ethereum Sepolia0xDB5492265f6038831E89f495670FF909aDe94bd9
    SolanaDZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe
    Acala0xe157115ef34c93145Fec2FE53706846853B07F42
    Algorand86525641
    Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
    Arbitrum Sepolia0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Avalanche0x61E44E506Ca5659E6c0bba9b678586fA2d729756
    Base Sepolia0x86F55A04690fd7815A3D802bD587e83eA888B239
    Berachain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Blast0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2
    BNB Smart Chain0x9dcF9D205C9De35334D646BeE44b2D2859712A09
    Celo0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153
    Fantom0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8
    HyperEVM0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
    Injectiveinj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh
    Ink0x376428e7f26D5867e69201b275553C45B09EE090
    Kaia0xC7A13BE098720840dEa132D860fDfa030884b09A
    Karura0xe157115ef34c93145Fec2FE53706846853B07F42
    Linea0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Mantle0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D
    Mezo0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780
    Monad0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659
    Moonbeam0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96
    NEARtoken.wormhole.testnet
    Neon0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0
    Oasis0x88d8004A9BdbfD9D28090A02010C19897a29605c
    Optimism Sepolia0x99737Ec4B815d816c49A385943baf0380e75c0Ac
    Polygon Amoy0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Scroll0x22427d90B7dA3fA4642F7025A854c7254E4e45BF
    Seisei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2
    Seievm0x23908A62110e21C04F3A4e011d24F901F911744A
    SNAXchain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Sui0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da
    Terraterra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a
    Terra 2.0terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk
    Unichain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    World Chain0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2
    X Layer0xdA91a06299BBF302091B053c6B9EF86Eff0f930D
    XPLAxpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x
    +
    Chain NameContract Address
    Ethereum Holesky0x76d093BbaE4529a342080546cAFEec4AcbA59EC6
    Ethereum Sepolia0xDB5492265f6038831E89f495670FF909aDe94bd9
    SolanaDZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe
    Algorand86525641
    Aptos0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f
    Arbitrum Sepolia0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Avalanche0x61E44E506Ca5659E6c0bba9b678586fA2d729756
    Base Sepolia0x86F55A04690fd7815A3D802bD587e83eA888B239
    Berachain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Blast0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2
    BNB Smart Chain0x9dcF9D205C9De35334D646BeE44b2D2859712A09
    Celo0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153
    Fantom0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8
    HyperEVM0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78
    Injectiveinj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh
    Ink0x376428e7f26D5867e69201b275553C45B09EE090
    Kaia0xC7A13BE098720840dEa132D860fDfa030884b09A
    Linea0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Mantle0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D
    Mezo0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780
    Monad0xF323dcDe4d33efe83cf455F78F9F6cc656e6B659
    Moonbeam0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96
    NEARtoken.wormhole.testnet
    Neon0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0
    Optimism Sepolia0x99737Ec4B815d816c49A385943baf0380e75c0Ac
    Polygon Amoy0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
    Scroll0x22427d90B7dA3fA4642F7025A854c7254E4e45BF
    Seisei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2
    Seievm0x23908A62110e21C04F3A4e011d24F901F911744A
    SNAXchain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    Sui0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da
    Terra 2.0terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk
    Unichain0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a
    World Chain0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2
    X Layer0xdA91a06299BBF302091B053c6B9EF86Eff0f930D
    === "Devnet" -
    Chain NameContract Address
    Ethereum0x0290FB167208Af455bB137780163b7B7a9a10C16
    SolanaB6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE
    Algorand1006
    Aptos0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31
    BNB Smart Chain0x0290FB167208Af455bB137780163b7B7a9a10C16
    NEARtoken.test.near
    Sui0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690
    Terraterra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6
    Terra 2.0terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6
    +
    Chain NameContract Address
    Ethereum0x0290FB167208Af455bB137780163b7B7a9a10C16
    SolanaB6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE
    Algorand1006
    Aptos0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31
    BNB Smart Chain0x0290FB167208Af455bB137780163b7B7a9a10C16
    NEARtoken.test.near
    Sui0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690
    Terra 2.0terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6
    diff --git a/.snippets/text/products/reference/testnet-faucets/testnet-faucets.md b/.snippets/text/products/reference/testnet-faucets/testnet-faucets.md index 3a927c97d..b83437214 100644 --- a/.snippets/text/products/reference/testnet-faucets/testnet-faucets.md +++ b/.snippets/text/products/reference/testnet-faucets/testnet-faucets.md @@ -5,7 +5,7 @@ ### EVM -
    TestnetEnvironmentTokenFaucet
    Ethereum HoleskyEVMETHAlchemy Faucet
    Ethereum SepoliaEVMETHAlchemy Faucet
    AcalaEVMACADiscord Faucet
    Arbitrum SepoliaEVMETHList of Faucets
    AvalancheEVMAVAXOfficial Avalanche Faucet
    Base SepoliaEVMETHList of Faucets
    BerachainEVMBERAOfficial Berachain Faucet
    BlastEVMETHList of Faucets
    BNB Smart ChainEVMBNBOfficial BNB Faucet
    CeloEVMCELOOfficial Celo Faucet
    FantomEVMFTMOfficial Fantom Faucet
    GnosisEVMxDAIOfficial Gnosis Faucet
    HyperEVMEVMmock USDCOfficial Hyperliquid Faucet
    InkEVMETHOfficial Ink Faucet
    KaiaEVMKAIAOfficial Kaia Faucet
    KaruraEVMACADiscord Faucet
    LineaEVMETHList of Faucets
    MantleEVMMNTOfficial Mantle Faucet
    MonadEVMMONOfficial Monad Faucet
    MoonbeamEVMDEVOfficial Moonbeam Faucet
    NeonEVMNEONOfficial Neon Faucet
    OasisEVMTESTOfficial Oasis Faucet
    Optimism SepoliaEVMETHSuperchain Faucet
    Polygon AmoyEVMPOLOfficial Polygon Faucet
    ScrollEVMETHList of Faucets
    UnichainEVMETHQuickNode Faucet
    World ChainEVMETHAlchemy Faucet
    X LayerEVMOKBX Layer Official Faucet
    +
    TestnetEnvironmentTokenFaucet
    Ethereum HoleskyEVMETHAlchemy Faucet
    Ethereum SepoliaEVMETHAlchemy Faucet
    Arbitrum SepoliaEVMETHList of Faucets
    AvalancheEVMAVAXOfficial Avalanche Faucet
    Base SepoliaEVMETHList of Faucets
    BerachainEVMBERAOfficial Berachain Faucet
    BlastEVMETHList of Faucets
    BNB Smart ChainEVMBNBOfficial BNB Faucet
    CeloEVMCELOOfficial Celo Faucet
    FantomEVMFTMOfficial Fantom Faucet
    GnosisEVMxDAIOfficial Gnosis Faucet
    HyperEVMEVMmock USDCOfficial Hyperliquid Faucet
    InkEVMETHOfficial Ink Faucet
    KaiaEVMKAIAOfficial Kaia Faucet
    LineaEVMETHList of Faucets
    MantleEVMMNTOfficial Mantle Faucet
    MonadEVMMONOfficial Monad Faucet
    MoonbeamEVMDEVOfficial Moonbeam Faucet
    NeonEVMNEONOfficial Neon Faucet
    Optimism SepoliaEVMETHSuperchain Faucet
    Polygon AmoyEVMPOLOfficial Polygon Faucet
    ScrollEVMETHList of Faucets
    UnichainEVMETHQuickNode Faucet
    World ChainEVMETHAlchemy Faucet
    X LayerEVMOKBX Layer Official Faucet
    ### SVM @@ -17,7 +17,7 @@ ### CosmWasm -
    TestnetEnvironmentTokenFaucet
    CelestiaCosmWasmTIADiscord Faucet
    Cosmos HubCosmWasmATOMDiscord Faucet
    EvmosCosmWasmTEVMOSOfficial Evmos Faucet
    InjectiveCosmWasmINJOfficial Injective Faucet
    KujiraCosmWasmKUJIDiscord Faucet
    NeutronCosmWasmNTRNList of Faucets
    NobleCosmWasmUSDCCircle Faucet
    OsmosisCosmWasmOSMOOfficial Osmosis Faucet
    SEDACosmWasmSEDAOfficial SEDA Faucet
    SeiCosmWasmSEISei Atlantic-2 Faucet
    TerraCosmWasmLUNATerra Official Faucet
    Terra 2.0CosmWasmLUNATerra Official Faucet
    XPLACosmWasmXPLAXPLA Official Faucet
    +
    TestnetEnvironmentTokenFaucet
    CelestiaCosmWasmTIADiscord Faucet
    Cosmos HubCosmWasmATOMDiscord Faucet
    EvmosCosmWasmTEVMOSOfficial Evmos Faucet
    InjectiveCosmWasmINJOfficial Injective Faucet
    KujiraCosmWasmKUJIDiscord Faucet
    NeutronCosmWasmNTRNList of Faucets
    NobleCosmWasmUSDCCircle Faucet
    OsmosisCosmWasmOSMOOfficial Osmosis Faucet
    SEDACosmWasmSEDAOfficial SEDA Faucet
    SeiCosmWasmSEISei Atlantic-2 Faucet
    Terra 2.0CosmWasmLUNATerra Official Faucet
    ### Move VM diff --git a/images/build/.DS_Store b/images/build/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..56d89804657408d7854d71d98c17245e1c4d17e2 GIT binary patch literal 6148 zcmeHK%Sr=55Ukc50)ph|aelyqe=vmj1^EG$KoG(T(RkjI-{q%S{XkeYf)_7R4c#@< z+cm@1VS5{Ztxvlx%qSVnO#)Ih;*LuhFd)0gl8OP)#nq=y~Zn&St%d|q<|EV0#e}D3V83OEw2(4rGONW0^bVw_o2}pd*PTE zpALo?0f-Bx!?=!Fg4jGk?1f_@Gc-#oF{xG~h9#Z(R&~8_OiVhgh7YTottJ$U+j)MA za#&APlmb#Q<8R4KnnaT1#Gd|Zq|II>aDYv^IqHN4|K2jq`Pq) o6ozQW#AwIdcsss{qO5Da=JQ@SCI+4PpcC~o;JV19z+Wry1y4s7>;M1& literal 0 HcmV?d00001 diff --git a/llms-files/llms-basics.txt b/llms-files/llms-basics.txt index 9a75e8ddd..5293dfd55 100644 --- a/llms-files/llms-basics.txt +++ b/llms-files/llms-basics.txt @@ -1892,44 +1892,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -4391,7 +4361,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -4409,7 +4378,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -4417,7 +4385,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -4426,12 +4393,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -4454,7 +4419,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -4466,15 +4430,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -4483,19 +4446,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4511,7 +4471,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -4520,7 +4479,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4530,12 +4488,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -4546,7 +4502,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -4559,7 +4514,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -4573,11 +4527,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -4585,19 +4537,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -4612,7 +4561,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -4620,7 +4568,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -4628,12 +4575,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -4644,7 +4589,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -4671,6 +4615,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -4690,6 +4635,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -4742,13 +4688,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -4975,7 +4926,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4988,13 +4938,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -5022,9 +4970,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 3a5a39a2c..b95f48d99 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -2914,44 +2914,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -3637,7 +3625,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -3655,7 +3642,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -3663,7 +3649,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -3672,12 +3657,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -3700,7 +3683,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -3712,15 +3694,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -3729,19 +3710,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3757,7 +3735,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -3766,7 +3743,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3776,12 +3752,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -3792,7 +3766,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -3805,7 +3778,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -3819,11 +3791,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -3831,19 +3801,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -3858,7 +3825,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -3866,7 +3832,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -3874,12 +3839,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -3890,7 +3853,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -3917,6 +3879,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -3936,6 +3899,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -3988,13 +3952,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -4221,7 +4190,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4234,13 +4202,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -4268,9 +4234,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 3c2201ec3..e4467e0ec 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -626,6 +626,8 @@ To use NTT, you must have a token already deployed on the source and destination ## Install NTT CLI +
    + The NTT CLI is recommended to deploy and manage your cross-chain token configuration. 1. Run the installation command in your terminal: @@ -1065,6 +1067,15 @@ Create a unique key pair for the NTT program: solana-keygen grind --starts-with ntt:1 --ignore-case ``` + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -1142,9 +1153,9 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt push --payer INSERT_YOUR_KEYPAIR_JSON ``` -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. +### Recovering Rent for Failed Solana Deployments + +Failed Solana deployments don't result in lost SOL. Instead, SOL may be locked in deployment buffer accounts that persist after interruptions. To recover these funds, refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on identifying and closing these buffer accounts. ## Where to Go Next @@ -1182,6 +1193,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + --- END CONTENT --- @@ -3870,44 +3889,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -4593,7 +4600,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -4611,7 +4617,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -4619,7 +4624,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -4628,12 +4632,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -4656,7 +4658,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -4668,15 +4669,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -4685,19 +4685,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4713,7 +4710,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -4722,7 +4718,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4732,12 +4727,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -4748,7 +4741,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -4761,7 +4753,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -4775,11 +4766,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -4787,19 +4776,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -4814,7 +4800,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -4822,7 +4807,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -4830,12 +4814,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -4846,7 +4828,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -4873,6 +4854,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -4892,6 +4874,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -4944,13 +4927,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -5177,7 +5165,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -5190,13 +5177,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -5224,9 +5209,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index a5a7190b2..34367d02c 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -2680,44 +2680,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -3403,7 +3391,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -3421,7 +3408,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -3429,7 +3415,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -3438,12 +3423,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -3466,7 +3449,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -3478,15 +3460,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -3495,19 +3476,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3523,7 +3501,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -3532,7 +3509,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3542,12 +3518,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -3558,7 +3532,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -3571,7 +3544,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -3585,11 +3557,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -3597,19 +3567,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -3624,7 +3591,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -3632,7 +3598,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -3640,12 +3605,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -3656,7 +3619,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -3683,6 +3645,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -3702,6 +3665,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -3754,13 +3718,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -3987,7 +3956,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4000,13 +3968,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -4034,9 +4000,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 484298771..3892c2027 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -37,7 +37,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Ethereum | 2 | 1 | | Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | -| Acala | 12 | 787 | | Algorand | 8 | mainnet-v1.0 | | Aptos | 22 | 1 | | Arbitrum | 23 | Arbitrum One-42161 | @@ -57,7 +56,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Injective | 19 | injective-1 | | Ink | 46 | | | Kaia | 13 | 8217 | -| Karura | 11 | 686 | | Kujira | 4002 | kaiyo-1 | | Linea | 38 | 59144 | | Mantle | 35 | 5000 | @@ -68,7 +66,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Neon | 17 | 245022934 | | Neutron | 4003 | neutron-1 | | Noble | 4009 | noble-1 | -| Oasis | 7 | 42262 | | Optimism | 24 | 10 | | Osmosis | 20 | osmosis-1 | | Polygon | 5 | 137 | @@ -82,19 +79,16 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | -| Terra | 3 | columbus-5 | | Terra 2.0 | 18 | phoenix-1 | | Unichain | 44 | | | World Chain | 45 | 480 | | X Layer | 37 | 196 | -| XPLA | 28 | dimension_37-1 | === "Testnet" | Ethereum Holesky | 10006 | Holesky-17000 | | Ethereum Sepolia | 10002 | Sepolia-11155111 | | Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | -| Acala | 12 | 597 | | Algorand | 8 | testnet-v1.0 | | Aptos | 22 | 2 | | Arbitrum Sepolia | 10003 | Sepolia-421614 | @@ -114,7 +108,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Injective | 19 | injective-888 | | Ink | 46 | 763373 | | Kaia | 13 | Kairos-1001 | -| Karura | 11 | 596 | | Kujira | 4002 | harpoon-4 | | Linea | 38 | 59141 | | Mantle | 35 | Sepolia-5003 | @@ -125,7 +118,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Neon | 17 | 245022940 | | Neutron | 4003 | pion-1 | | Noble | 4009 | grand-1 | -| Oasis | 7 | 42261 | | Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | | Osmosis | 20 | osmo-test-5 | | Polygon Amoy | 10007 | Amoy-80002 | @@ -139,12 +131,10 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | -| Terra | 3 | bombay-12 | | Terra 2.0 | 18 | pisco-1 | | Unichain | 44 | Unichain Sepolia-1301 | | World Chain | 45 | 4801 | | X Layer | 37 | 195 | -| XPLA | 28 | cube_47-5 | --- END CONTENT --- @@ -164,7 +154,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -182,7 +171,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -190,7 +178,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -199,12 +186,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -227,7 +212,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -239,15 +223,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -256,19 +239,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -284,7 +264,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -293,7 +272,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -303,12 +281,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -319,7 +295,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -332,7 +307,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -346,11 +320,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -358,19 +330,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -385,7 +354,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -393,7 +361,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -401,12 +368,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -417,7 +382,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -444,6 +408,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -463,6 +428,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -515,13 +481,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -748,7 +719,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -761,13 +731,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -795,9 +763,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index df28c1ef9..fd5d958ad 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -2433,44 +2433,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -3156,7 +3144,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -3174,7 +3161,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -3182,7 +3168,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -3191,12 +3176,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -3219,7 +3202,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -3231,15 +3213,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -3248,19 +3229,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3276,7 +3254,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -3285,7 +3262,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3295,12 +3271,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -3311,7 +3285,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -3324,7 +3297,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -3338,11 +3310,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -3350,19 +3320,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -3377,7 +3344,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -3385,7 +3351,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -3393,12 +3358,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -3409,7 +3372,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -3436,6 +3398,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -3455,6 +3418,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -3507,13 +3471,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -3740,7 +3709,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -3753,13 +3721,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -3787,9 +3753,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 04db1e53f..f1059e783 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -16,8 +16,6 @@ You are an AI developer assistant for Wormhole (https://wormhole.com). Your task Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] ## Full content for each doc page @@ -407,355 +405,9 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: - [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. -- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- - -# Build on the Wormhole Liquidity Layer - -## Introduction - -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. - -## EVM Functions - -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - -See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. - -### Fast Market Order - -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` - -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` - -??? interface "Parameters `placeFastMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - - --- - - `maxFee` ++"uint128"++ - - The maximum fee the user wants to pay to execute a fast transfer. - - --- - - `deadline` ++"uint32"++ - - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. - -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. - -### Market Order - -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. - -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` - -??? interface "Parameters `placeMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- - -# Run a Wormhole Settlement Solver - -## Introduction - -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. - -A Solver is an off-chain agent responsible for: - -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana - -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. - -## Background - -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: - -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners - -These instructions work together to carry out the auction as follows: - -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. - -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. - -## Testnet Example Solver - -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. - -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. - -### Prerequisites - -In order to build and install dependencies locally in this repo, you will need: - -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} - -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: - -```sh -make dependencies -``` - -### Set up Config - -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. - -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - } - ] -} -``` - -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. - -### Listen to Activity - -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. - -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` - -You should see output resembling: - -
    - Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
    - -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: - -=== "Linux" - - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` - -=== "MacOS" - - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` - -### Running the Example Solver - -Using the same config for your publisher, run the example solver with the command below. - -```sh -CONFIG=path/to/config.json make run-solver -``` - -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. - -This process reads the following environment variables: - -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` - -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. - -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. - -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. - -An address lookup table is required to execute some transactions. Use the command below to create one. - -```sh -CONFIG=path/to/config.json make create-lut -``` - -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. - -The example solver has the following toggles depending on which orders you want to fulfill: - -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` - -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. - -This example solver does NOT do the following: - -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/settlement/overview/ --- BEGIN CONTENT --- --- @@ -766,19 +418,20 @@ categories: Settlement, Transfer # Settlement Overview -Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. +Wormhole Settlement is a multichain transfer system that allows users to specify what they want to happen, such as sending or swapping tokens, without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. -Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. +Settlement prioritizes speed, execution quality, and reliability. Its primary route, Mayan Swift, leverages fast off-chain auctions among a curated set of solvers to achieve low-latency bridging with minimal slippage. All settlement steps remain verifiable on-chain through Wormhole messages. -It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. +For broader use cases and protocol-level execution, Mayan MCTP provides an alternative path. It wraps Circle’s CCTP to facilitate native USDC bridging and token delivery in a single, verifiable flow. While slower due to chain finality constraints, MCTP offers a reliable mechanism for cross-chain transfers. ## Key Features - **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. - **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. -- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Fast and fallback-capable**: Combines high-speed execution with a reliable fallback path. - **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. -- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. +- **On-chain verifiability**: Even though auctions are off-chain, all settlement steps remain verifiable on-chain via Wormhole messages. +- **Two integrated routes**: Mayan Swift for speed, Mayan MCTP for compatibility and redundancy. ## How It Works @@ -787,7 +440,7 @@ At the core of Settlement are two components: - **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. - **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. -Settlement leverages the following three integrated protocols. +Settlement currently supports the following integrated protocols. ### Mayan Swift @@ -797,7 +450,7 @@ The diagram below shows how Mayan Swift handles a cross-chain intent when a user 1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. 2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. -3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +3. **User receives WIF**: Once the user receives WIF, a second VAA is emitted to finalize the transfer and releases the ETH held in the escrow to the solver. 4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. ```mermaid @@ -823,27 +476,9 @@ sequenceDiagram Escrow->>Solver_ARB: Releases ETH to solver ``` -### Liquidity Layer - -The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. - ### Mayan MCTP -Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. - -### One Integration, Three Ways - -Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. - -By default, Settlement integrates all three: - -- The SDK automatically resolves the best route for each transfer. -- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. -- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. - -Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. - -To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift. While typically more expensive due to protocol fees, it ensures reliable settlement when faster options are unavailable. ## Use Cases @@ -867,8 +502,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: - **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. -- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. -- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. +- **[Architecture Documentation](/docs/products/settlement/concepts/architecture/)**: Explore the Settlement architecture and components. --- END CONTENT --- ## Basics Concepts [shared: true] @@ -2753,44 +2387,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -3476,7 +3098,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -3494,7 +3115,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -3502,7 +3122,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -3511,12 +3130,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -3539,7 +3156,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -3551,15 +3167,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -3568,19 +3183,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3596,7 +3208,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -3605,7 +3216,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3615,12 +3225,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -3631,7 +3239,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -3644,7 +3251,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -3658,11 +3264,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -3670,19 +3274,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -3697,7 +3298,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -3705,7 +3305,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -3713,12 +3312,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -3729,7 +3326,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -3756,6 +3352,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -3775,6 +3372,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -3827,13 +3425,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -4060,7 +3663,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4073,13 +3675,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -4107,9 +3707,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 69a76639d..047f267f6 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -3486,44 +3486,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -4209,7 +4197,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -4227,7 +4214,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -4235,7 +4221,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -4244,12 +4229,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -4272,7 +4255,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -4284,15 +4266,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -4301,19 +4282,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4329,7 +4307,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -4338,7 +4315,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -4348,12 +4324,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -4364,7 +4338,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -4377,7 +4350,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -4391,11 +4363,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -4403,19 +4373,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -4430,7 +4397,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -4438,7 +4404,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -4446,12 +4411,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -4462,7 +4425,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -4489,6 +4451,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -4508,6 +4471,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -4560,13 +4524,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -4793,7 +4762,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4806,13 +4774,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -4840,9 +4806,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index 0626669d3..793a2055a 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -868,7 +868,7 @@ The primary functions of the Token Bridge contracts revolve around: - **Transferring tokens** - locking and minting tokens across chains - **Transferring tokens with a payload** - including additional data with transfers -### Attest a token +### Attest a Token Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. @@ -899,6 +899,20 @@ function attestToken( A unique identifier for the attestation transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.attestToken{value: wormholeFee}( + address(tokenImpl), // the token contract to attest + 234 // nonce for the transfer +); + ``` + When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. @@ -957,6 +971,25 @@ function transferTokens( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokens{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + arbiterFee, // fee for relayer + nonce // nonce for this transfer +); + ``` + Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. ```solidity @@ -973,7 +1006,7 @@ function completeTransfer(bytes memory encodedVm) external; - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -### Transfer tokens with payload +### Transfer Tokens with Payload While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. @@ -1027,6 +1060,25 @@ function transferTokensWithPayload( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokensWithPayload{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + nonce, // nonce for this transfer + additionalPayload // additional payload data +); + ``` + After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. @@ -3024,44 +3076,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -3747,7 +3787,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -3765,7 +3804,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -3773,7 +3811,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -3782,12 +3819,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -3810,7 +3845,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -3822,15 +3856,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -3839,19 +3872,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3867,7 +3897,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -3876,7 +3905,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -3886,12 +3914,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -3902,7 +3928,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -3915,7 +3940,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -3929,11 +3953,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -3941,19 +3963,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -3968,7 +3987,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -3976,7 +3994,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -3984,12 +4001,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -4000,7 +4015,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -4027,6 +4041,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -4046,6 +4061,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -4098,13 +4114,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -4331,7 +4352,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -4344,13 +4364,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -4378,9 +4396,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index a88de1a98..ae9924130 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -44,8 +44,6 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md [type: other] -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md [type: other] Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md [type: other] @@ -3608,24 +3606,6 @@ Your selected blockchain network determines the available wallet options when us The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. - -### CoinGecko API Key {: #coingecko-api-key } - -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. - -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - coinGeckoApiKey: 'INSERT_API_KEY', -}; - -function App() { - return ; -} -``` --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ @@ -5335,6 +5315,8 @@ To use NTT, you must have a token already deployed on the source and destination ## Install NTT CLI +
    + The NTT CLI is recommended to deploy and manage your cross-chain token configuration. 1. Run the installation command in your terminal: @@ -5774,6 +5756,15 @@ Create a unique key pair for the NTT program: solana-keygen grind --starts-with ntt:1 --ignore-case ``` + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -5851,9 +5842,9 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt push --payer INSERT_YOUR_KEYPAIR_JSON ``` -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. +### Recovering Rent for Failed Solana Deployments + +Failed Solana deployments don't result in lost SOL. Instead, SOL may be locked in deployment buffer accounts that persist after interruptions. To recover these funds, refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on identifying and closing these buffer accounts. ## Where to Go Next @@ -5891,6 +5882,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + --- END CONTENT --- @@ -7150,355 +7149,9 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: - [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. -- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- - -# Build on the Wormhole Liquidity Layer - -## Introduction - -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. - -## EVM Functions - -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - -See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. - -### Fast Market Order - -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` - -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` - -??? interface "Parameters `placeFastMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - - --- - - `maxFee` ++"uint128"++ - - The maximum fee the user wants to pay to execute a fast transfer. - - --- - - `deadline` ++"uint32"++ - - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. - -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. - -### Market Order - -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. - -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` - -??? interface "Parameters `placeMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- - -# Run a Wormhole Settlement Solver - -## Introduction - -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. - -A Solver is an off-chain agent responsible for: - -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana - -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. - -## Background - -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: - -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners - -These instructions work together to carry out the auction as follows: - -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. - -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. - -## Testnet Example Solver - -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. - -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. - -### Prerequisites - -In order to build and install dependencies locally in this repo, you will need: - -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} - -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: - -```sh -make dependencies -``` - -### Set up Config - -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. - -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - } - ] -} -``` - -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. - -### Listen to Activity - -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. - -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` - -You should see output resembling: - -
    - Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
    - -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: - -=== "Linux" - - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` - -=== "MacOS" - - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` - -### Running the Example Solver - -Using the same config for your publisher, run the example solver with the command below. - -```sh -CONFIG=path/to/config.json make run-solver -``` - -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. - -This process reads the following environment variables: - -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` - -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. - -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. - -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. - -An address lookup table is required to execute some transactions. Use the command below to create one. - -```sh -CONFIG=path/to/config.json make create-lut -``` - -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. - -The example solver has the following toggles depending on which orders you want to fulfill: - -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` - -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. - -This example solver does NOT do the following: - -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/settlement/overview/ --- BEGIN CONTENT --- --- @@ -7509,19 +7162,20 @@ categories: Settlement, Transfer # Settlement Overview -Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. +Wormhole Settlement is a multichain transfer system that allows users to specify what they want to happen, such as sending or swapping tokens, without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. -Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. +Settlement prioritizes speed, execution quality, and reliability. Its primary route, Mayan Swift, leverages fast off-chain auctions among a curated set of solvers to achieve low-latency bridging with minimal slippage. All settlement steps remain verifiable on-chain through Wormhole messages. -It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. +For broader use cases and protocol-level execution, Mayan MCTP provides an alternative path. It wraps Circle’s CCTP to facilitate native USDC bridging and token delivery in a single, verifiable flow. While slower due to chain finality constraints, MCTP offers a reliable mechanism for cross-chain transfers. ## Key Features - **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. - **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. -- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Fast and fallback-capable**: Combines high-speed execution with a reliable fallback path. - **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. -- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. +- **On-chain verifiability**: Even though auctions are off-chain, all settlement steps remain verifiable on-chain via Wormhole messages. +- **Two integrated routes**: Mayan Swift for speed, Mayan MCTP for compatibility and redundancy. ## How It Works @@ -7530,7 +7184,7 @@ At the core of Settlement are two components: - **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. - **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. -Settlement leverages the following three integrated protocols. +Settlement currently supports the following integrated protocols. ### Mayan Swift @@ -7540,7 +7194,7 @@ The diagram below shows how Mayan Swift handles a cross-chain intent when a user 1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. 2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. -3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +3. **User receives WIF**: Once the user receives WIF, a second VAA is emitted to finalize the transfer and releases the ETH held in the escrow to the solver. 4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. ```mermaid @@ -7566,27 +7220,9 @@ sequenceDiagram Escrow->>Solver_ARB: Releases ETH to solver ``` -### Liquidity Layer - -The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. - ### Mayan MCTP -Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. - -### One Integration, Three Ways - -Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. - -By default, Settlement integrates all three: - -- The SDK automatically resolves the best route for each transfer. -- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. -- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. - -Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. - -To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift. While typically more expensive due to protocol fees, it ensures reliable settlement when faster options are unavailable. ## Use Cases @@ -7610,8 +7246,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: - **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. -- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. -- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. +- **[Architecture Documentation](/docs/products/settlement/concepts/architecture/)**: Explore the Settlement architecture and components. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/transfer-flow/ @@ -7886,7 +7521,7 @@ The primary functions of the Token Bridge contracts revolve around: - **Transferring tokens** - locking and minting tokens across chains - **Transferring tokens with a payload** - including additional data with transfers -### Attest a token +### Attest a Token Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. @@ -7917,6 +7552,20 @@ function attestToken( A unique identifier for the attestation transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.attestToken{value: wormholeFee}( + address(tokenImpl), // the token contract to attest + 234 // nonce for the transfer +); + ``` + When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. @@ -7975,6 +7624,25 @@ function transferTokens( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokens{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + arbiterFee, // fee for relayer + nonce // nonce for this transfer +); + ``` + Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. ```solidity @@ -7991,7 +7659,7 @@ function completeTransfer(bytes memory encodedVm) external; - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -### Transfer tokens with payload +### Transfer Tokens with Payload While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. @@ -8045,6 +7713,25 @@ function transferTokensWithPayload( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokensWithPayload{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + nonce, // nonce for this transfer + additionalPayload // additional payload data +); + ``` + After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. @@ -10042,44 +9729,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -10765,7 +10440,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -10783,7 +10457,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -10791,7 +10464,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -10800,12 +10472,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -10828,7 +10498,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -10840,15 +10509,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -10857,19 +10525,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -10885,7 +10550,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -10894,7 +10558,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -10904,12 +10567,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -10920,7 +10581,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -10933,7 +10593,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -10947,11 +10606,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -10959,19 +10616,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -10986,7 +10640,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -10994,7 +10647,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -11002,12 +10654,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -11018,7 +10668,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -11045,6 +10694,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -11064,6 +10714,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -11116,13 +10767,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -11349,7 +11005,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -11362,13 +11017,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -11396,9 +11049,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 43b401849..f7514099d 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -2635,7 +2635,7 @@ The VAA's body combines the Envelope and Payload. The Wormhole Guardians signed When integrating protocols like Token Bridge or Wormhole Relayer: - The TypeScript SDK handles VAAs off-chain, focusing on deserialization, validation, and payload extraction before submission -- The Solidity SDK processes VAAs on-chain, using libraries like `VaaLib` to decode and execute protocol actions +- The Solidity SDK processes VAAs on-chain, using libraries like [`VaaLib`](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/VaaLib.sol){target=\_blank} to decode and execute protocol actions ## VAAs in Protocol Contexts @@ -5727,44 +5727,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. --- END CONTENT --- @@ -6450,7 +6438,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -6468,7 +6455,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -6476,7 +6462,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -6485,12 +6470,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -6513,7 +6496,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -6525,15 +6507,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -6542,19 +6523,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -6570,7 +6548,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -6579,7 +6556,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -6589,12 +6565,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -6605,7 +6579,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -6618,7 +6591,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -6632,11 +6604,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -6644,19 +6614,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -6671,7 +6638,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -6679,7 +6645,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -6687,12 +6652,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -6703,7 +6666,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -6730,6 +6692,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -6749,6 +6712,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -6801,13 +6765,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -7034,7 +7003,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -7047,13 +7015,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -7081,9 +7047,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM diff --git a/llms-full.txt b/llms-full.txt index 267c77156..0aba98680 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -69,10 +69,7 @@ Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/re Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/concepts/architecture.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/faqs.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/get-started.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/liquidity-layer.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/guides/solver.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/overview.md -Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/settlement/tutorials/.settlement-routes.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/payload-structure.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/concepts/transfer-flow.md Doc-Page: https://raw.githubusercontent.com/wormhole-foundation/wormhole-docs/refs/heads/main/products/token-bridge/faqs.md @@ -4760,24 +4757,6 @@ Your selected blockchain network determines the available wallet options when us The wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration. If you would like to offer Reown Cloud (formerly WalletConnect) as a supported wallet option, you'll need to obtain a project ID on the [Reown Cloud dashboard](https://cloud.reown.com/){target=\_blank}. - -### CoinGecko API Key {: #coingecko-api-key } - -The CoinGecko API can be used to fetch token price data. If you have a [CoinGecko API Plan](https://apiguide.coingecko.com/getting-started/getting-started){target=\_blank}, you can include the API key in the configuration. - -```jsx -import WormholeConnect, { - WormholeConnectConfig, -} from '@wormhole-foundation/wormhole-connect'; - -const config: WormholeConnectConfig = { - coinGeckoApiKey: 'INSERT_API_KEY', -}; - -function App() { - return ; -} -``` --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/connect/configuration/theme/ @@ -12272,6 +12251,8 @@ To use NTT, you must have a token already deployed on the source and destination ## Install NTT CLI +
    + The NTT CLI is recommended to deploy and manage your cross-chain token configuration. 1. Run the installation command in your terminal: @@ -12711,6 +12692,15 @@ Create a unique key pair for the NTT program: solana-keygen grind --starts-with ntt:1 --ignore-case ``` + +### Generate an NTT Program Key Pair + +Create a unique key pair for the NTT program: + + ```bash + solana-keygen grind --starts-with ntt:1 --ignore-case + ``` + ### Set Mint Authority If you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on Solana. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions. @@ -12788,9 +12778,9 @@ After setting up your deployment, finalize the configuration and deploy the NTT ntt push --payer INSERT_YOUR_KEYPAIR_JSON ``` -### Troubleshoot Deployment Issues - -If your deployment fails, it may be due to leftover program buffer accounts taking up storage on Solana. These temporary accounts are created during deployment but may persist if interrupted. Refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on finding and closing these buffer accounts to free up space and allow redeployment. +### Recovering Rent for Failed Solana Deployments + +Failed Solana deployments don't result in lost SOL. Instead, SOL may be locked in deployment buffer accounts that persist after interruptions. To recover these funds, refer to the [Solana program deployment guide](https://solana.com/docs/programs/deploying#program-buffer-accounts){target=\_blank} for instructions on identifying and closing these buffer accounts. ## Where to Go Next @@ -12828,6 +12818,14 @@ If your deployment fails, it may be due to leftover program buffer accounts taki [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs){target=\_blank} +- :octicons-question-16:{ .lg .middle } **View FAQs** + + --- + + Find answers to common questions about NTT. + + [:custom-arrow: View FAQs](/docs/build/transfers/native-token-transfers/faqs){target=\_blank} + --- END CONTENT --- @@ -14500,7 +14498,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Ethereum | 2 | 1 | | Solana | 1 | Mainnet Beta-5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d | -| Acala | 12 | 787 | | Algorand | 8 | mainnet-v1.0 | | Aptos | 22 | 1 | | Arbitrum | 23 | Arbitrum One-42161 | @@ -14520,7 +14517,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Injective | 19 | injective-1 | | Ink | 46 | | | Kaia | 13 | 8217 | -| Karura | 11 | 686 | | Kujira | 4002 | kaiyo-1 | | Linea | 38 | 59144 | | Mantle | 35 | 5000 | @@ -14531,7 +14527,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Neon | 17 | 245022934 | | Neutron | 4003 | neutron-1 | | Noble | 4009 | noble-1 | -| Oasis | 7 | 42262 | | Optimism | 24 | 10 | | Osmosis | 20 | osmosis-1 | | Polygon | 5 | 137 | @@ -14545,19 +14540,16 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sonic | 52 | 146 | | Stargaze | 4005 | stargaze-1 | | Sui | 21 | 35834a8a | -| Terra | 3 | columbus-5 | | Terra 2.0 | 18 | phoenix-1 | | Unichain | 44 | | | World Chain | 45 | 480 | | X Layer | 37 | 196 | -| XPLA | 28 | dimension_37-1 | === "Testnet" | Ethereum Holesky | 10006 | Holesky-17000 | | Ethereum Sepolia | 10002 | Sepolia-11155111 | | Solana | 1 | Devnet-EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG | -| Acala | 12 | 597 | | Algorand | 8 | testnet-v1.0 | | Aptos | 22 | 2 | | Arbitrum Sepolia | 10003 | Sepolia-421614 | @@ -14577,7 +14569,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Injective | 19 | injective-888 | | Ink | 46 | 763373 | | Kaia | 13 | Kairos-1001 | -| Karura | 11 | 596 | | Kujira | 4002 | harpoon-4 | | Linea | 38 | 59141 | | Mantle | 35 | Sepolia-5003 | @@ -14588,7 +14579,6 @@ The following table documents the chain IDs used by Wormhole and places them alo | Neon | 17 | 245022940 | | Neutron | 4003 | pion-1 | | Noble | 4009 | grand-1 | -| Oasis | 7 | 42261 | | Optimism Sepolia | 10005 | Optimism Sepolia-11155420 | | Osmosis | 20 | osmo-test-5 | | Polygon Amoy | 10007 | Amoy-80002 | @@ -14602,12 +14592,10 @@ The following table documents the chain IDs used by Wormhole and places them alo | Sonic | 52 | 57054 | | Stargaze | 4005 | | | Sui | 21 | 4c78adac | -| Terra | 3 | bombay-12 | | Terra 2.0 | 18 | pisco-1 | | Unichain | 44 | Unichain Sepolia-1301 | | World Chain | 45 | 4801 | | X Layer | 37 | 195 | -| XPLA | 28 | cube_47-5 | --- END CONTENT --- @@ -14627,7 +14615,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Ethereum | 200 | 201 | | finalized | ~ 19min | Details | | Solana | | 0 | 1 | | ~ 14s | Details | -| Acala | 200 | 201 | | finalized | ~ 24s | | | Algorand | | | 0 | | ~ 4s | Details | | Aptos | | | 0 | | ~ 4s | Details | | Arbitrum | 200 | 201 | | finalized | ~ 18min | Details | @@ -14645,7 +14632,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Injective | | | 0 | | ~ 3s | | | Ink | | | 0 | | ~ 9min | | | Kaia | 200 | | | finalized | ~ 1s | | -| Karura | 200 | 201 | | finalized | ~ 24s | Details | | Kujira | | | 0 | | ~ 3s | | | Mantle | 200 | 201 | | finalized | ~ 18min | | | Mezo | | | 0 | | ~ 8s | | @@ -14653,7 +14639,6 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Moonbeam | 200 | 201 | | finalized | ~ 24s | Details | | NEAR | | | 0 | | ~ 2s | Details | | Neutron | | | 0 | | ~ 5s | | -| Oasis | 200 | | | finalized | ~ 12s | | | Optimism | 200 | 201 | | finalized | ~ 18min | | | Osmosis | | | 0 | | ~ 6s | | | Polygon | 200 | | | finalized | ~ 66s | Details | @@ -14662,12 +14647,10 @@ The following table documents each chain's `consistencyLevel` values (i.e., fina | Sonic | | | 0 | | ~ 1s | | | Stargaze | | | 0 | | ~ 5s | | | Sui | | | 0 | | ~ 3s | Details | -| Terra | | | 0 | | ~ 6s | | | Terra 2.0 | | | 0 | | ~ 6s | | | Unichain | 200 | 201 | | finalized | ~ 18min | | | World Chain | | | 0 | | ~ 18min | | | X Layer | 200 | 201 | | finalized | ~ 16min | | -| XPLA | | | 0 | | ~ 5s | | --- END CONTENT --- @@ -14690,7 +14673,6 @@ categories: Reference | Ethereum | 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B | | Solana | worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth | -| Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Algorand | 842125965 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum | 0xa5f208e072434bC67592E4C49C1B991BA79BCA46 | @@ -14702,15 +14684,14 @@ categories: Reference | Celo | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Fantom | 0x126783A6Cb203a3E35344528B26ca3a0489a1485 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| HyperEVM | 0x7C0faFc4384551f063e05aee704ab943b8B53aB3 | | Injective | inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d | | Ink | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | Kaia | 0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7 | -| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Mantle | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Moonbeam | 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3 | | NEAR | contract.wormhole_crypto.near | | Neutron | neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh | -| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Optimism | 0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722 | | Polygon | 0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7 | | Pythnet | H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU | @@ -14719,19 +14700,16 @@ categories: Reference | Seievm | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | SNAXchain | 0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 | | Sui | 0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c | -| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | | Terra 2.0 | terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp | | Unichain | 0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D | | World Chain | 0xcbcEe4e081464A15d8Ad5f58BB493954421eB506 | | X Layer | 0x194B123c5E96B9b2E49763619985790Dc241CAC0 | -| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | === "Testnet" | Ethereum Holesky | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Ethereum Sepolia | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | | Solana | 3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5 | -| Acala | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Algorand | 86525623 | | Aptos | 0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625 | | Arbitrum Sepolia | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -14747,7 +14725,6 @@ categories: Reference | Injective | inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg | | Ink | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Kaia | 0x1830CC6eE66c84D2F177B94D544967c774E624cA | -| Karura | 0x64fb09E405D2043ed7785a29E296C766D56F2056 | | Linea | 0x79A1027a6A159502049F10906D333EC57E95F083 | | Mantle | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Mezo | 0x268557122Ffd64c85750d630b716471118F323c8 | @@ -14756,7 +14733,6 @@ categories: Reference | NEAR | wormhole.wormhole.testnet | | Neon | 0x268557122Ffd64c85750d630b716471118F323c8 | | Neutron | neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4 | -| Oasis | 0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb | | Optimism Sepolia | 0x31377888146f3253211EFEf5c676D41ECe7D58Fe | | Osmosis | osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx | | Polygon Amoy | 0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35 | @@ -14766,12 +14742,10 @@ categories: Reference | Seievm | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | SNAXchain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | Sui | 0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790 | -| Terra | terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v | | Terra 2.0 | terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0 | | Unichain | 0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd | | World Chain | 0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A | | X Layer | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | -| XPLA | xpla1upkjn4mthr0047kahvn0llqx4qpqfn75lnph4jpxfn8walmm8mqsanyy35 | === "Devnet" @@ -14782,7 +14756,6 @@ categories: Reference | BNB Smart Chain | 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550 | | NEAR | wormhole.test.near | | Sui | 0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0 | -| Terra | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | | Terra 2.0 | terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au | @@ -14795,7 +14768,6 @@ categories: Reference | Ethereum | 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 | | Solana | wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb | -| Acala | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Algorand | 842126029 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum | 0x0b2402144Bb366A632D14B83F244D2e0e21bD39c | @@ -14809,11 +14781,9 @@ categories: Reference | Injective | inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn | | Ink | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | Kaia | 0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F | -| Karura | 0xae9d7fe007b3327AA64A32824Aaac52C42a6E624 | | Mantle | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | | Moonbeam | 0xb1731c586ca89a23809861c6103f0b96b3f57d92 | | NEAR | contract.portalbridge.near | -| Oasis | 0x5848C791e09901b40A9Ef749f2a6735b418d7564 | | Optimism | 0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b | | Polygon | 0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE | | Scroll | 0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d | @@ -14821,19 +14791,16 @@ categories: Reference | Seievm | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | SNAXchain | 0x8B94bfE456B48a6025b92E11Be393BAa86e68410 | | Sui | 0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9 | -| Terra | terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf | | Terra 2.0 | terra153366q50k7t8nn7gec00hg66crnhkdggpgdtaxltaq6xrutkkz3s992fw9 | | Unichain | 0x3Ff72741fd67D6AD0668d93B41a09248F4700560 | | World Chain | 0xc309275443519adca74c9136b02A38eF96E3a1f6 | | X Layer | 0x5537857664B0f9eFe38C9f320F75fEf23234D904 | -| XPLA | xpla137w0wfch2dfmz7jl2ap8pcmswasj8kg06ay4dtjzw7tzkn77ufxqfw7acv | === "Testnet" | Ethereum Holesky | 0x76d093BbaE4529a342080546cAFEec4AcbA59EC6 | | Ethereum Sepolia | 0xDB5492265f6038831E89f495670FF909aDe94bd9 | | Solana | DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe | -| Acala | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Algorand | 86525641 | | Aptos | 0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f | | Arbitrum Sepolia | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | @@ -14848,7 +14815,6 @@ categories: Reference | Injective | inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh | | Ink | 0x376428e7f26D5867e69201b275553C45B09EE090 | | Kaia | 0xC7A13BE098720840dEa132D860fDfa030884b09A | -| Karura | 0xe157115ef34c93145Fec2FE53706846853B07F42 | | Linea | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Mantle | 0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D | | Mezo | 0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780 | @@ -14856,7 +14822,6 @@ categories: Reference | Moonbeam | 0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96 | | NEAR | token.wormhole.testnet | | Neon | 0xEe3dB83916Ccdc3593b734F7F2d16D630F39F1D0 | -| Oasis | 0x88d8004A9BdbfD9D28090A02010C19897a29605c | | Optimism Sepolia | 0x99737Ec4B815d816c49A385943baf0380e75c0Ac | | Polygon Amoy | 0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e | | Scroll | 0x22427d90B7dA3fA4642F7025A854c7254E4e45BF | @@ -14864,12 +14829,10 @@ categories: Reference | Seievm | 0x23908A62110e21C04F3A4e011d24F901F911744A | | SNAXchain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | Sui | 0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da | -| Terra | terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a | | Terra 2.0 | terra1c02vds4uhgtrmcw7ldlg75zumdqxr8hwf7npseuf2h58jzhpgjxsgmwkvk | | Unichain | 0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a | | World Chain | 0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2 | | X Layer | 0xdA91a06299BBF302091B053c6B9EF86Eff0f930D | -| XPLA | xpla1kek6zgdaxcsu35nqfsyvs2t9vs87dqkkq6hjdgczacysjn67vt8sern93x | === "Devnet" @@ -14880,7 +14843,6 @@ categories: Reference | BNB Smart Chain | 0x0290FB167208Af455bB137780163b7B7a9a10C16 | | NEAR | token.test.near | | Sui | 0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690 | -| Terra | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | | Terra 2.0 | terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6 | @@ -14907,6 +14869,7 @@ categories: Reference | Optimism | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Polygon | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Scroll | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | +| Seievm | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | SNAXchain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | Unichain | 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 | | World Chain | 0x1520cc9e779c56dab5866bebfb885c86840c33d3 | @@ -14926,6 +14889,7 @@ categories: Reference | Monad | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Moonbeam | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 | | Optimism Sepolia | 0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE | +| Polygon Amoy | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Seievm | 0x362fca37E45fe1096b42021b543f462D49a5C8df | | Unichain | 0x362fca37E45fe1096b42021b543f462D49a5C8df | @@ -14978,13 +14942,18 @@ categories: Reference === "Mainnet" - | Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | + | Acala | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | +| Corn | 0xa683c66045ad16abb1bCE5ad46A64d95f9A25785 | | Gnosis | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | Goat | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Karura | 0xa321448d90d4e5b0A732867c18eA198e75CAC48E | | LightLink | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Oasis | 0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585 | | Rootstock | 0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6 | | Sonic | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | | Telos | 0x352A86168e6988A1aDF9A15Cb00017AAd3B67155 | +| Terra | terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5 | +| XPLA | xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w | !!!note Read-only deployments allow Wormhole messages to be received on chains not fully integrated with Wormhole Guardians. These deployments support cross-chain data verification but cannot originate messages. For example, a governance message can be sent from a fully integrated chain and processed on a read-only chain, but the read-only chain cannot send messages back. @@ -15288,7 +15257,6 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Ethereum Holesky | EVM | ETH | Alchemy Faucet | | Ethereum Sepolia | EVM | ETH | Alchemy Faucet | -| Acala | EVM | ACA | Discord Faucet | | Arbitrum Sepolia | EVM | ETH | List of Faucets | | Avalanche | EVM | AVAX | Official Avalanche Faucet | | Base Sepolia | EVM | ETH | List of Faucets | @@ -15301,13 +15269,11 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | HyperEVM | EVM | mock USDC | Official Hyperliquid Faucet | | Ink | EVM | ETH | Official Ink Faucet | | Kaia | EVM | KAIA | Official Kaia Faucet | -| Karura | EVM | ACA | Discord Faucet | | Linea | EVM | ETH | List of Faucets | | Mantle | EVM | MNT | Official Mantle Faucet | | Monad | EVM | MON | Official Monad Faucet | | Moonbeam | EVM | DEV | Official Moonbeam Faucet | | Neon | EVM | NEON | Official Neon Faucet | -| Oasis | EVM | TEST | Official Oasis Faucet | | Optimism Sepolia | EVM | ETH | Superchain Faucet | | Polygon Amoy | EVM | POL | Official Polygon Faucet | | Scroll | EVM | ETH | List of Faucets | @@ -15335,9 +15301,7 @@ Don't let the need for testnet tokens get in the way of buildling your next grea | Osmosis | CosmWasm | OSMO | Official Osmosis Faucet | | SEDA | CosmWasm | SEDA | Official SEDA Faucet | | Sei | CosmWasm | SEI | Sei Atlantic-2 Faucet | -| Terra | CosmWasm | LUNA | Terra Official Faucet | | Terra 2.0 | CosmWasm | LUNA | Terra Official Faucet | -| XPLA | CosmWasm | XPLA | XPLA Official Faucet | ### Move VM @@ -15893,355 +15857,9 @@ You can tailor the example to your use case by adjusting: Once you've chosen a path, follow the corresponding guide to start building: - [**`demo-mayanswift`**](https://github.com/wormhole-foundation/demo-mayanswift){target=_blank}: Check out the repository for the full code example. -- [**Integrate with Liquidity Layer**](/docs/products/settlement/guides/liquidity-layer/): Interact directly with routers for flexible protocol-level control. --- END CONTENT --- -Doc-Content: https://wormhole.com/docs/products/settlement/guides/liquidity-layer/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Liquidity Layer -description: Learn how to build on the Wormhole Liquidity Layer, the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. -categories: Settlement, Transfer ---- - -# Build on the Wormhole Liquidity Layer - -## Introduction - -The Wormhole Liquidity Layer is the underlying chain abstraction infrastructure layer for protocols across Wormhole-connected ecosystems. It allows these protocols to bundle call data containing arbitrary actions that can be executed atomically alongside each transfer. This feature enables developers to create fully chain-abstracted user experiences, including constructing natively cross-chain decentralized exchanges (DEXs), borrow-lend protocols, payment protocols, and other applications atop this layer. The following section describes the key smart contract components for teams seeking to build atop Wormhole Settlement. - -## EVM Functions - -The EVM Token Router is a simple interface against which to integrate. For an integrator, the contracts have two main entry points: `placeMarketOrder` and `placeFastMarketOrder`. - -See the complete list of [Token Router contract addresses](/docs/products/reference/contract-addresses/#settlement-token-router){target=\_blank} for supported networks. - -### Fast Market Order - -The `placeFastMarketOrder` function allows the caller to elect for a _faster-than-finality_ transfer of USDC (with an arbitrary message payload) to the destination chain by setting the `maxFee` and `deadline` parameters. Using this interface does not guarantee that the caller's transfer will be delivered faster than finality; however, any willing market participants can compete for the specified `maxFee` by participating in an auction on the Solana `MatchingEngine` - -```solidity title="`placeFastMarketOrder` Interface" -function placeFastMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, - uint128 maxFee, - uint32 deadline -) external payable returns (uint64 sequence, uint64 fastSequence); -``` - -??? interface "Parameters `placeFastMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - - --- - - `maxFee` ++"uint128"++ - - The maximum fee the user wants to pay to execute a fast transfer. - - --- - - `deadline` ++"uint32"++ - - The deadline for the fast transfer auction to start. Note: This timestamp should be for the `MatchingEngine` chain (such as Solana) to avoid any clock drift issues between different blockchains. Integrators can set this value to `0` if they don't want to use a deadline. - -The `placeFastMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. - -### Market Order - -The `placeMarketOrder` function is a _wait-for-full-finality_ USDC transfer with an arbitrary message payload. The Swap Layer, built on top of the Wormhole Settlement, uses this function if the auction on the matching engine for `placeFastMarketOrder` doesn't start within a specific deadline. - -```solidity title="`placeMarketOrder` Interface" -function placeMarketOrder( - uint128 amountIn, - uint16 targetChain, - bytes32 redeemer, - bytes calldata redeemerMessage, -) external payable returns (uint64 sequence, uint64 protocolSequence); -``` - -??? interface "Parameters `placeMarketOrder()`" - - `amountIn` ++"uint128"++ - - The amount to transfer. - - --- - - `targetChain` ++"uint16"++ - - Target chain ID. - - --- - - `redeemer` ++"bytes32"++ - - Redeemer contract address. - - --- - - `redeemerMessage` ++"bytes"++ - - An arbitrary payload for the redeemer. - -The `placeMarketOrder` function returns a sequence number for the Wormhole Fill message. This function requires the caller to provide a `msg.value` equal to the amount returned by the `messageFee()` function on the `IWormhole.sol` interface. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/guides/solver/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlement Solver -description: Set up, configure, and run a Wormhole Settlement Solver on Solana's Matching Engine to fulfill cross-chain transfers efficiently and securely. -categories: Settlement, Transfer ---- - -# Run a Wormhole Settlement Solver - -## Introduction - -This page provides instructions on how to set up, configure, and run a Solver for Wormhole Settlement using the [example solver](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/update-solver-example/solver){target=\_blank}. - -A Solver is an off-chain agent responsible for: - -- Listening to cross-chain transfer requests sent over Wormhole -- Bidding in auctions (on Solana) to fulfill each request -- Facilitating the actual cross-chain transfer by locking/burning assets on Solana and minting/unlocking them on the destination chain -- Rebalancing once the origin chain transaction finalizes and is redeemed back on Solana - -For information on how the protocol functions and its core features, please visit the [Wormhole Settlement](/docs/products/settlement/overview/){target=\_blank} page. - -## Background - -The Solana Matching Engine's permissionless English auction is a central component of Wormhole Settlement protocol architecture. The Matching Engine contract allows any third-party solver to interact with the matching engine to place bids or improve existing ones. The contract includes four key instructions: - -1. `initialize_auction` - creates a new auction account on-chain and sets basic parameters like the auction's token mint, the amount required, and the bidding period details -2. `bid` - allows a solver to place or update a bid on the active auction -3. `finalize_auction` - following the conclusion of the auction, this instruction completes the fast transfer by sending funds to the recipient on the target chain. This instruction may call the Circle CCTP contract or release an NTT contract in the future, depending on the shuttle asset in question. Failure to execute this message within a predefined grace period may result in a penalty for the winning bidder. -4. `cancel_auction` - cancels an open auction when the auction is no longer valid or was created by mistake. The program returns all locked funds to their respective owners - -These instructions work together to carry out the auction as follows: - -- The solver transfers the bid amount to the program escrow account, which ensures they have liquidity -- With each successful call of `bid`, the program updates the auction to the new highest bidder, and the prior bid is atomically sent back to the originating solver -- The originating solver can repurpose the returned funds and use them to improve their bid -- Following the auction, the winning solver has to call an instruction on the matching engine to execute the intent - -When placing a bid, whether initial or improved, the solver must deposit the required funds plus a security deposit into the matching engine contract. In this permissionless auction, the requirement of this principal amount plus the security deposit ensures a solver's credible commitment to fulfill the transfer. Malicious actors could place hollow bids without this safeguard, undermining the auction's credibility and hindering true price discovery. - -If the winning solver fails to call the `finalize_auction` instruction, other competing solvers may permissionlessly 'slash' the solver by executing the instruction on their behalf and collecting a portion of the original security deposit as a reward. The remaining portion is routed to the user as compensation for the unanticipated delay. This mechanism properly incentivizes timely execution through solver redundancy and competition. - -## Testnet Example Solver - -You can clone the Wormhole [`example-liquidity-layer`](https://github.com/wormholelabs-xyz/example-liquidity-layer){target=\_blank} repository to use the included [`solver`](https://github.com/wormholelabs-xyz/example-liquidity-layer/tree/main/solver){target=\_blank} directory as an example solver to fulfill fast orders by interacting with the Matching Engine on Solana. - -!!!warning - This example is not optimized for performance, has only been tested on Solana devnet, and is not intended for production use. Any assumptions made in this example may not translate to mainnet. - -### Prerequisites - -In order to build and install dependencies locally in this repo, you will need: - -- node v20.18.1 -- npmv - get started by installing `nvm` using this [installation guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating){target=\_blank} - -Navigate into the `solver` directory, then run the command below to set up your environment and install the node dependencies and Matching Engine package: - -```sh -make dependencies -``` - -### Set up Config - -The following is an example of a `config.json` file for Solana devnet. The keys here are required for both the publisher and example solver processes. - -```json title="config.json" -{ - "environment": "Testnet", - "zmqChannels": { - "fastVaa": "tcp://localhost:6001", - "finalizedVaa": "tcp://localhost:6002" - }, - "publisher": { - "log": { - "level": "info" - }, - "vaaSpy": { - "host": "localhost:7073", - "enableObservationCleanup": true, - "observationSeenThresholdMs": 1500000, - "observationCleanupIntervalMs": 500, - "observationsToRemovePerInterval": 5, - "delayedThresholdMs": 60000 - } - }, - "solver": { - "log": { - "level": "info", - "filename": "logs/solver.log" - }, - "connection": { - "rpc": "", - "maxTransactionsPerSecond": 5, - "commitment": "processed", - "addressLookupTable": "YourAddressLookupTab1eHere11111111111111111", - "matchingEngine": "mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS", - "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "knownAtaOwners": [ - "Payer11111111111111111111111111111111111111", - "Payer11111111111111111111111111111111111112", - "Payer11111111111111111111111111111111111113" - ] - } - }, - "routerEndpoints": [ - { - "chain": "Sepolia", - "endpoint": "0xE57D917bf955FedE2888AAbD056202a6497F1882", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Avalanche", - "endpoint": "0x8Cd7D7C980cd72eBD16737dC3fa04469dcFcf07A", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "OptimismSepolia", - "endpoint": "0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "ArbitrumSepolia", - "endpoint": "0xe0418C44F06B0b0D7D1706E01706316DBB0B210E", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "BaseSepolia", - "endpoint": "0x824Ea687CD1CC2f2446235D33Ae764CbCd08e18C", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - }, - { - "chain": "Polygon", - "endpoint": "0xa098368AaaDc0FdF3e309cda710D7A5f8BDEeCD9", - "rollbackRisk": 0.0069, - "offerEdge": 0.042 - } - ] -} -``` - -The rollback risks and offer edges configured in the sample config are arbitrary placeholders. You should use historical data and your risk tolerance, to determine appropriate values for your project. - -### Listen to Activity - -The example solver listens to attested Wormhole messages (VAAs) published on the Wormhole Guardian gossip network. To listen to this gossip network and run the VAA publisher, run the command below. Docker compose is used to listen to the Pyth Beacon and start the [`publishActivity`](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/publishActivity.ts){target=\_blank} process. - -```sh -NETWORK=testnet CONFIG=path/to/config.json make run-publisher -``` - -You should see output resembling: - -
    - Start logging with info level. - 2025-01-21 16:38:28.145 [publisher] info: Environment: Testnet - 2025-01-21 16:38:36.631 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33635, vaaTime=1737499116 - 2025-01-21 16:38:51.044 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33637, vaaTime=1737499130 - 2025-01-21 16:40:24.890 [publisher] info: Fast VAA. chain=OptimismSepolia, sequence=33639, vaaTime=1737499224 -
    - -To set up the Pyth Beacon (which is run using make `run-publisher`), you may need to increase the UDP buffer size for the OS: - -=== "Linux" - - ```sh - sudo sysctl -w net.core.rmem_max=2097152 - sudo sysctl -w net.core.rmem_default=2097152 - ``` - -=== "MacOS" - - ```sh - sudo sysctl -w net.inet.udp.recvspace=2097152 - ``` - -### Running the Example Solver - -Using the same config for your publisher, run the example solver with the command below. - -```sh -CONFIG=path/to/config.json make run-solver -``` - -It is recommended you write log output to a file so errors can be tracked. The example config above specifies an example log filename. - -This process reads the following environment variables: - -```sh -SOLANA_PRIVATE_KEY_1= -SOLANA_PRIVATE_KEY_2= -SOLANA_PRIVATE_KEY_3= -SOLANA_PRIVATE_KEY_4= -SOLANA_PRIVATE_KEY_5= -``` - -At least one of these environment variables must be defined as a keypair encoded in base64 format. These payers must have SOL to send transactions on Solana devnet. If they need funds, they can request them from the [Solana devnet faucet](https://faucet.solana.com/){target=\_blank}. - -The example solver assumes that these payers own USDC Associated Token Accounts(ATAs), which will be used to fulfill fast transfers. These ATAs must be funded with Solana Devnet USDC. If your ATAs need funds, request some at the [Circle testnet faucet](https://faucet.circle.com/){target=\_blank}. - -Wallets and their corresponding ATA will be disabled if there are insufficient funds to pay for transactions or fulfill fast transfers. These constraints can be modified using the `updatePayerMinimumLamports` and `updateTokenMinimumBalance` methods. - -An address lookup table is required to execute some transactions. Use the command below to create one. - -```sh -CONFIG=path/to/config.json make create-lut -``` - -`SOLANA_PRIVATE_KEY_1` must be defined for this script to work. - -The example solver has the following toggles depending on which orders you want to fulfill: - -- `enableCctpOrderPipeline()` -- `enableLocalOrderPipeline()` -- `enablePlaceInitialOffer()` -- `enableImproveOffer()` - -See the comments in [runExampleSolver](https://github.com/wormholelabs-xyz/example-liquidity-layer/blob/update-solver-example/solver/app/runExampleSolver.ts){target=\_blank} for more information. - -This example solver does NOT do the following: - -- Discriminate between the CCTP source networks. You must add logic to determine whether you want to constrain fulfilling orders from specific networks. This solver will try to fulfill all orders as long as `enableCctpOrderPipeline()` is called -- Discriminate among fulfillment sizes. No logic determines how small or large fast order transfer sizes should be. This solver will try to fulfill anything as long as your balance can handle it -- Add auctions to auction history. We recommend that after settling a complete auction (one that you have won), you write the auction pubkey to a database and have a separate process to add auction history entries to reclaim rent from these auction accounts. The auction history time delay is two hours after the VAA timestamp. This example does not prescribe any specific database, so add whichever you want ---- END CONTENT --- - Doc-Content: https://wormhole.com/docs/products/settlement/overview/ --- BEGIN CONTENT --- --- @@ -16252,19 +15870,20 @@ categories: Settlement, Transfer # Settlement Overview -Wormhole Settlement is a multichain transfer system that allows users to describe the transfer they want to make without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. +Wormhole Settlement is a multichain transfer system that allows users to specify what they want to happen, such as sending or swapping tokens, without handling the execution themselves. Instead, off-chain agents called solvers compete to fulfill these user intents. -Settlement was built to address liquidity fragmentation across chains. Traditionally, solvers had to split their capital between multiple networks, which reduced efficiency and scalability. Settlement solves this by consolidating liquidity on Solana, enabling faster execution and minimal slippage, even as liquidity and supported chains scale. +Settlement prioritizes speed, execution quality, and reliability. Its primary route, Mayan Swift, leverages fast off-chain auctions among a curated set of solvers to achieve low-latency bridging with minimal slippage. All settlement steps remain verifiable on-chain through Wormhole messages. -It combines three complementary protocols into a single integration suite, allowing developers to select the best execution route based on cost, speed, and asset requirements. +For broader use cases and protocol-level execution, Mayan MCTP provides an alternative path. It wraps Circle’s CCTP to facilitate native USDC bridging and token delivery in a single, verifiable flow. While slower due to chain finality constraints, MCTP offers a reliable mechanism for cross-chain transfers. ## Key Features - **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it. - **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality. -- **Unified liquidity**: Liquidity is concentrated on Solana, reducing fragmentation and facilitating easier scaling. +- **Fast and fallback-capable**: Combines high-speed execution with a reliable fallback path. - **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT. -- **Three interchangeable routes**: Each with distinct tradeoffs in speed, cost, and protocol requirements. +- **On-chain verifiability**: Even though auctions are off-chain, all settlement steps remain verifiable on-chain via Wormhole messages. +- **Two integrated routes**: Mayan Swift for speed, Mayan MCTP for compatibility and redundancy. ## How It Works @@ -16273,7 +15892,7 @@ At the core of Settlement are two components: - **Intents**: Signed transactions where a user defines what outcome they want (e.g., send USDC to another chain and receive ETH). It abstracts what the user wants, not how it should be executed. - **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return. -Settlement leverages the following three integrated protocols. +Settlement currently supports the following integrated protocols. ### Mayan Swift @@ -16283,7 +15902,7 @@ The diagram below shows how Mayan Swift handles a cross-chain intent when a user 1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum. 2. **VAA emitted to Solana**: A [Verifiable Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\_blank} triggers the solver to release SOL on Solana, which is swapped to WIF using an aggregator. -3. **User receives WIF**: Once the user receives WIF, a second VAA finalizes the transfer and releases the ETH held in the escrow to the solver. +3. **User receives WIF**: Once the user receives WIF, a second VAA is emitted to finalize the transfer and releases the ETH held in the escrow to the solver. 4. **Failure handling**: If any step fails, the ETH in escrow is either retained or returned to the user — the solver only gets paid if execution succeeds. ```mermaid @@ -16309,27 +15928,9 @@ sequenceDiagram Escrow->>Solver_ARB: Releases ETH to solver ``` -### Liquidity Layer - -The Liquidity Layer utilizes a hub-and-spoke architecture, with Solana serving as the central hub for liquidity. Solvers only need to provide liquidity on Solana, eliminating the need for cross-chain inventory management. This route relies on USDC and NTT as shuttle assets and executes transactions in roughly 15 to 25 seconds. Solvers participate in on-chain English auctions to win execution rights and front the necessary assets to fulfill user intents. The design removes the need for rebalancing, making it more scalable and capital-efficient, especially for high-volume or frequently used applications. - ### Mayan MCTP -Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift or the Liquidity Layer. While typically more expensive due to protocol fees, it’s a reliable way to ensure settlement completion in edge cases. - -### One Integration, Three Ways - -Settlement isn't about choosing just one route; it’s a protocol suite in which all three architectures work together to maximize coverage, speed, and reliability. - -By default, Settlement integrates all three: - -- The SDK automatically resolves the best route for each transfer. -- If a fast route like Mayan Swift is unavailable, it can fall back to Liquidity Layer or MCTP. -- This redundancy ensures better uptime, pricing, and a smoother user experience without requiring additional logic. - -Developers can customize route preferences, but for most applications, no configuration is needed to benefit from the full suite. - -To read more about each protocol, check the [architecture documentation](/docs/products/settlement/concepts/architecture/){target=\_blank}. +Mayan MCTP is a fallback protocol that wraps Circle’s CCTP into the Settlement framework. It bundles USDC bridging and swaps into a single operation handled by protocol logic. This route is slower due to its reliance on chain finality. However, it provides broad compatibility and redundancy, making it useful when faster routes are unavailable or when targeting chains that aren’t supported by Swift. While typically more expensive due to protocol fees, it ensures reliable settlement when faster options are unavailable. ## Use Cases @@ -16353,167 +15954,7 @@ To read more about each protocol, check the [architecture documentation](/docs/p Start building with Settlement or dive deeper into specific components: - **[Get Started with Settlement](/docs/products/settlement/get-started/)**: Follow a hands-on demo using Mayan Swift. -- **[Build on the Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/)**: Integrate the hub-and-spoke model. -- **[Run a Solver](/docs/products/settlement/guides/solver/)**: Operate a solver and participate in auctions. ---- END CONTENT --- - -Doc-Content: https://wormhole.com/docs/products/settlement/tutorials/.settlement-routes/ ---- BEGIN CONTENT --- ---- -title: Wormhole Settlements -description: Learn how to integrate Wormhole Settlement Routes using the SDK to simplify cross-chain swaps, manage fees, and execute seamless transactions. ---- - -# Integrate Wormhole Settlement Routes Using the SDK - -## Introduction - -This guide explains integrating Wormhole Settlement Routes from the Wormhole SDK into your application. These Routes abstract the complexity of cross-chain token swaps by handling route discovery, fee estimation, and transaction construction, all useful for dApps seeking to embed cross-chain swaps. By following this tutorial you will install the Wormhole SDK Route package, configure and execute a swap, and explore error handling and troubleshooting. - -## Prerequisites - -Before beginning this project, make sure you have the following: - -- **Wormhole SDK Route package** - installed using your preferred package manager - - To install the package with npm, run the following command in your terminal: - - ```sh - npm install @mayan-finance/wormhole-sdk-route - ``` - - Alternatively, clone the repository and install dependencies: - - ```sh - git clone https://github.com/mayan-finance/wormhole-sdk-route.git - cd wormhole-sdk-route - npm install - ``` - -- **Data for parameters** - you will need: - - - [Chain IDs](/docs/products/reference/chain-ids/){target=\_blank} for the source and destination chains - - An contract address for the token you want to swap and the token you want to receive on the destination chain - -## Configure and Setup - -To initiate a swap, you must create a configuration object that specifies all required parameters. These typically include: - -- `sourceChain` - identifier for the chain where the swap begins -- `destinationChain` - identifier for the target chain -- `inputTokenAddress` - address of the token you want to swap -- `outputTokenAddress` - identifier/address of the desired token on the destination chain -- `amount` - the amount to swap (expressed in the smallest unit, e.g., wei for Ethereum) -- `slippageTolerance` - acceptable percentage of slippage (e.g., 0.005 for 0.5%) - -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - -const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', // Example token on Solana - amount: '1000000000000000000', // For instance, 1 token in wei - slippageTolerance: 0.005, // 0.5% slippage tolerance - // Additional parameters may be included as needed -}; - -const swapRoute = new SwapRoute(config); -``` - -## Execute a Swap - -Once the configuration is complete, the next steps are to retrieve the optimal swap route and execute the transaction. - -### Fetch the Swap Route - -Before sending a transaction, fetch the optimal swap route to review details such as fees and expected outputs: - -```ts -async function getSwapDetails() { - try { - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - return routeDetails; - } catch (error) { - console.error('Error fetching swap route:', error); - throw error; - } -} - -getSwapDetails(); -``` - -### Execute the Swap Transaction - -Once the route is confirmed, execute the swap: - -```ts -async function executeSwap() { - try { - const txResponse = await swapRoute.executeSwap(); - console.log('Swap executed successfully:', txResponse); - // Further transaction handling (e.g., waiting for confirmation) can be added here. - } catch (error) { - console.error('Swap execution failed:', error); - } -} - -executeSwap(); -``` - -## Complete Example Integration - -Below is a complete example that puts together configuration, route fetching, and swap execution: - -```ts -import { SwapRoute, SwapRouteConfig } from '@mayan-finance/wormhole-sdk-route'; - -async function performSwap() { - // Configure the swap parameters - const config: SwapRouteConfig = { - sourceChain: 'ethereum', - destinationChain: 'solana', - inputTokenAddress: '0xYourInputTokenAddress', - outputTokenAddress: 'So11111111111111111111111111111111111111112', - amount: '1000000000000000000', - slippageTolerance: 0.005, - // Include additional settings as needed - }; - - // Initialize the swap route - const swapRoute = new SwapRoute(config); - - try { - // Retrieve the optimal swap route details - const routeDetails = await swapRoute.getRoute(); - console.log('Optimal Swap Route:', routeDetails); - - // Execute the swap transaction - const txResponse = await swapRoute.executeSwap(); - console.log('Swap Transaction Response:', txResponse); - } catch (error) { - console.error('An error occurred during the swap process:', error); - } -} - -performSwap(); -``` - -## Error Handling and Troubleshooting - -- **Route fetching errors** - ensure all configuration parameters (chain IDs, token addresses, amounts) are correct and that network endpoints are reachable -- **Transaction execution errors** - verify that the connected wallet has sufficient funds and that transaction parameters meet the network’s requirements. Detailed logging can assist with troubleshooting -- **Miscellaneous** - to pass a `ReferrerAddress` to the initiation functions, you can create a class that extends the `MayanRoute` class. Override the `referrerAddress` method to return addresses by platform, as shown in this example: - - ```ts - class MayanRefRoute extends MayanRoute { - override referrerAddress(): ReferrerAddresses | undefined { - return { evm: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbe" }; - } - } - ``` +- **[Architecture Documentation](/docs/products/settlement/concepts/architecture/)**: Explore the Settlement architecture and components. --- END CONTENT --- Doc-Content: https://wormhole.com/docs/products/token-bridge/concepts/payload-structure/ @@ -17362,7 +16803,7 @@ The primary functions of the Token Bridge contracts revolve around: - **Transferring tokens** - locking and minting tokens across chains - **Transferring tokens with a payload** - including additional data with transfers -### Attest a token +### Attest a Token Suppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so the Token Bridge can recognize it and create a wrapped version if necessary. @@ -17393,6 +16834,20 @@ function attestToken( A unique identifier for the attestation transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.attestToken{value: wormholeFee}( + address(tokenImpl), // the token contract to attest + 234 // nonce for the transfer +); + ``` + When `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish. You must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata. @@ -17451,6 +16906,25 @@ function transferTokens( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokens{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + arbiterFee, // fee for relayer + nonce // nonce for this transfer +); + ``` + Once a transfer VAA is obtained from the Wormhole Guardian network, the final step is to redeem the tokens on the destination chain. Redemption verifies the VAA's authenticity and releases (or mints) tokens to the specified recipient. To redeem the tokens, call `completeTransfer()`. ```solidity @@ -17467,7 +16941,7 @@ function completeTransfer(bytes memory encodedVm) external; - The Token Bridge normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain -### Transfer tokens with payload +### Transfer Tokens with Payload While a standard token transfer moves tokens between chains, a transfer with a payload allows you to embed arbitrary data in the VAA. This data can be used on the destination chain to execute additional logic—such as automatically depositing tokens into a DeFi protocol, initiating a swap on a DEX, or interacting with a custom smart contract. @@ -17521,6 +16995,25 @@ function transferTokensWithPayload( A unique identifier for the transfer transaction. +??? interface "Example" + + ```solidity + IWormhole wormhole = IWormhole(wormholeAddr); +ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr); + +// Get the fee for publishing a message +uint256 wormholeFee = wormhole.messageFee(); + +tokenBridge.transferTokensWithPayload{value: wormholeFee}( + token, // address of the ERC-20 token to transfer + amount, // amount of tokens to transfer + recipientChain, // Wormhole chain ID of the destination chain + recipient, // recipient address on the destination chain (as bytes32) + nonce, // nonce for this transfer + additionalPayload // additional payload data +); + ``` + After initiating a transfer on the source chain, the Wormhole Guardian network observes and signs the resulting message, creating a Verifiable Action Approval (VAA). You'll need to fetch this VAA and then call `completeTransferWithPayload()`. Only the designated recipient contract can redeem tokens. This ensures that the intended contract securely handles the attached payload. On successful redemption, the tokens are minted (if foreign) or released (if native) to the recipient address on the destination chain. For payload transfers, the designated contract can execute the payload's logic at this time. @@ -19019,9 +18512,6 @@ Once running, a [gRPC](https://grpc.io/){target=\_blank} client (i.e., your prog Use this [proto-spec file](https://github.com/wormhole-foundation/wormhole/blob/main/proto/spy/v1/spy.proto){target=\_blank} to generate a client for the gRPC service. -!!! note - If using JavaScript/TypeScript, the [Spydk](https://www.npmjs.com/package/@certusone/wormhole-spydk){target=\_blank} makes setting up a client easier. - ## Data Persistence The Spy does not have a built-in persistence layer, so it is typically paired with something like Redis or an SQL database to record relevant messages. @@ -19728,44 +19218,44 @@ Interoperability is a critical challenge in the rapidly evolving blockchain land Critical problems Wormhole addresses include: -- **Blockchain isolation** - Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks -- **Cross-chain complexity** - by abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications -- **Security and decentralization** - Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions +- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks. +- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications. +- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions. ## What Does Wormhole Offer? Wormhole provides a suite of tools and protocols that support a wide range of use cases: -- **Cross-chain messaging** - securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications (xDapps) -- **Asset transfers** - facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank} -- **Developer tools** - leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently +- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications. +- **Asset transfers**: Facilitate the movement of tokens and NFTs across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\_blank}. +- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\_blank}, [Solidity SDK](/docs/tools/solidity-sdk/get-started/), [Wormholescan](https://wormholescan.io/){target=\_blank}, and the [Wormholescan API](https://wormholescan.io/#/developers/api-doc){target=\_blank} and documentation to build and deploy cross-chain applications quickly and efficiently. ## What Isn't Wormhole? -- **Wormhole is _not_ a blockchain** - it acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself -- **Wormhole is _not_ a token bridge** - while it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge +- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself. +- **Wormhole is _not_ a token bridge**: While it facilitates token transfers, Wormhole also supports a wide range of cross-chain applications, making it much more versatile than a typical bridge. ## Use Cases of Wormhole Consider the following examples of potential applications enabled by Wormhole: -- **Cross-chain exchange** - using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access -- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}** - NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals -- **Cross-chain game** - games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum +- **Cross-chain exchange**: Using [Wormhole Connect](/docs/products/connect/overview/){target=\_blank}, developers can build exchanges that allow deposits from any Wormhole-connected chain, significantly increasing liquidity access. +- **[Cross-chain governance](https://wormhole.com/blog/stake-for-governance-is-now-live-for-w-token-holders){target=\_blank}**: NFT collections on different networks can use Wormhole to communicate votes cast on their respective chains to a designated "voting" chain for combined proposals +- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued as NFTs on another network, such as Ethereum. ## Explore Discover more about the Wormhole ecosystem, components, and protocols: -- **[Architecture](/docs/protocol/architecture/){target=\_blank}** - explore the components of the protocol -- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}** - learn about the protocols built on top of Wormhole +- **[Architecture](/docs/protocol/architecture/){target=\_blank}**: Explore the components of the protocol. +- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\_blank}**: Learn about the protocols built on top of Wormhole. ## Demos Demos offer more realistic implementations than tutorials: -- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}** - quickly set up a project with the Scaffolding repository -- **[xDapp Book Projects](https://github.com/wormhole-foundation/xdapp-book/tree/main/projects){target=\_blank}** - run and learn from example programs +- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\_blank}**: Quickly set up a project with the Scaffolding repository. +- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains. @@ -4912,7 +4903,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4925,14 +4915,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-multigov.txt b/llms-files/llms-multigov.txt index 41d092714..1a36d0173 100644 --- a/llms-files/llms-multigov.txt +++ b/llms-files/llms-multigov.txt @@ -4046,7 +4046,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4059,7 +4058,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4069,17 +4067,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4097,7 +4093,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4112,7 +4107,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4120,7 +4114,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4128,12 +4121,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4172,7 +4163,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4185,14 +4175,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-ntt.txt b/llms-files/llms-ntt.txt index 4de90a307..e6a6d462c 100644 --- a/llms-files/llms-ntt.txt +++ b/llms-files/llms-ntt.txt @@ -5046,7 +5046,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5059,7 +5058,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5069,17 +5067,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5097,7 +5093,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5112,7 +5107,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5120,7 +5114,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5128,12 +5121,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5172,7 +5163,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -5185,14 +5175,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-queries.txt b/llms-files/llms-queries.txt index cb6d9c5b9..501df49a3 100644 --- a/llms-files/llms-queries.txt +++ b/llms-files/llms-queries.txt @@ -60,7 +60,7 @@ The Guardian node calculates an ECDSA signature using [`Sign` function of the cr ```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` -See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. +See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_signer.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. !!! note If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. @@ -3812,7 +3812,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3825,7 +3824,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3835,17 +3833,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3863,7 +3859,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3878,7 +3873,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3886,7 +3880,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3894,12 +3887,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3938,7 +3929,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3951,14 +3941,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-reference.txt b/llms-files/llms-reference.txt index 3892c2027..a39d66c2d 100644 --- a/llms-files/llms-reference.txt +++ b/llms-files/llms-reference.txt @@ -537,7 +537,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -550,7 +549,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -560,17 +558,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -588,7 +584,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -603,7 +598,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -611,7 +605,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -619,12 +612,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -663,7 +654,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -676,14 +666,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-relayers.txt b/llms-files/llms-relayers.txt index 5184107c7..43bcf31d3 100644 --- a/llms-files/llms-relayers.txt +++ b/llms-files/llms-relayers.txt @@ -3565,7 +3565,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3578,7 +3577,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3588,17 +3586,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3616,7 +3612,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3631,7 +3626,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3639,7 +3633,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3647,12 +3640,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3691,7 +3682,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3704,14 +3694,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-settlement.txt b/llms-files/llms-settlement.txt index 99cb9ebb7..f96518ed9 100644 --- a/llms-files/llms-settlement.txt +++ b/llms-files/llms-settlement.txt @@ -123,7 +123,6 @@ The protocol provides mechanisms for unlocking the fee once the bridging process ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- @@ -3519,7 +3518,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3532,7 +3530,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3542,17 +3539,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3570,7 +3565,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3585,7 +3579,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3593,7 +3586,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3601,12 +3593,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3645,7 +3635,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -3658,14 +3647,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-solidity-sdk.txt b/llms-files/llms-solidity-sdk.txt index 34134a50e..cbb48642b 100644 --- a/llms-files/llms-solidity-sdk.txt +++ b/llms-files/llms-solidity-sdk.txt @@ -4618,7 +4618,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4631,7 +4630,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4641,17 +4639,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4669,7 +4665,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4684,7 +4679,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4692,7 +4686,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4700,12 +4693,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4744,7 +4735,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4757,14 +4747,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-token-bridge.txt b/llms-files/llms-token-bridge.txt index bfe38d379..f31be1974 100644 --- a/llms-files/llms-token-bridge.txt +++ b/llms-files/llms-token-bridge.txt @@ -4208,7 +4208,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4221,7 +4220,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4231,17 +4229,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4259,7 +4255,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4274,7 +4269,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4282,7 +4276,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4290,12 +4283,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4334,7 +4325,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -4347,14 +4337,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-transfer.txt b/llms-files/llms-transfer.txt index 8b786dcab..7d3cf204b 100644 --- a/llms-files/llms-transfer.txt +++ b/llms-files/llms-transfer.txt @@ -6896,7 +6896,6 @@ The protocol provides mechanisms for unlocking the fee once the bridging process ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT --- @@ -10890,7 +10889,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10903,7 +10901,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10913,17 +10910,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10941,7 +10936,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10956,7 +10950,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10964,7 +10957,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -10972,12 +10964,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -11016,7 +11006,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -11029,14 +11018,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-files/llms-typescript-sdk.txt b/llms-files/llms-typescript-sdk.txt index 36a189dad..1c927c4bd 100644 --- a/llms-files/llms-typescript-sdk.txt +++ b/llms-files/llms-typescript-sdk.txt @@ -6859,7 +6859,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6872,7 +6871,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6882,17 +6880,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6910,7 +6906,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6925,7 +6920,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6933,7 +6927,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6941,12 +6934,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6985,7 +6976,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -6998,14 +6988,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | diff --git a/llms-full.txt b/llms-full.txt index 481b31102..63104a10b 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -13768,7 +13768,7 @@ The Guardian node calculates an ECDSA signature using [`Sign` function of the cr ```keccak256("query_response_0000000000000000000|"+keccak256(responseBytes))``` -See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_key.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. +See the [Guardian Key Usage](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0009_guardian_signer.md){target=\_blank} white paper for more background. Once this signature is created, the Guardian's index in the Guardian set is appended to the end. !!! note If you are used to `ecrecover` you will notice that the `v` byte is `0` or `1` as opposed to `27` or `28`. The `signaturesToEvmStruct` method in the [Query TypeScript SDK](https://npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`. @@ -15105,7 +15105,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Polygon | EVM | :white_check_mark: | :x: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :x: | :x: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15118,7 +15117,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15128,17 +15126,15 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Celo | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Fantom | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Gnosis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| HyperEVM | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | +| HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15156,7 +15152,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Algorand | AVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Aptos | Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15171,7 +15166,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Injective | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Ink | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15179,7 +15173,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | NEAR | NEAR VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :x: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15187,12 +15180,10 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Seievm | EVM | :white_check_mark: | :white_check_mark: | :x: | | | SNAXchain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Sui | Sui Move VM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Terra | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Terra 2.0 | CosmWasm | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Unichain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | World Chain | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | X Layer | EVM | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| XPLA | CosmWasm | :white_check_mark: | :white_check_mark: | :x: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15231,7 +15222,6 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | Ethereum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Solana | SVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Acala | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Arbitrum | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Avalanche | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Base | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15244,14 +15234,12 @@ Wormhole supports many blockchains across mainnet, testnet, and devnets. You can | HyperEVM | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Ink | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Kaia | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Karura | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs | | Linea | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mantle | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Mezo | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Monad | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Moonbeam | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Neon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | -| Oasis | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Optimism | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Polygon | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | | Scroll | EVM | :white_check_mark: | :white_check_mark: | :white_check_mark: | :material-web:Website:material-file-document:Developer Docs:octicons-package-16:Block Explorer | @@ -15605,7 +15593,6 @@ The protocol provides mechanisms for unlocking the fee once the bridging process ## Where to Go Next -- To learn more about available EVM functions, see the [Build on the Wormhole Liquidity Layer](/docs/products/settlement/guides/liquidity-layer/){target=\_blank} guide - To learn how to integrate settlement routes into your application, see the [Integrate Wormhole Settlement Routes Using the SDK](https://github.com/wormhole-foundation/demo-mayanswift){target=\_blank} tutorial --- END CONTENT ---